diff --git a/doc/x3/quick_reference.qbk b/doc/x3/quick_reference.qbk
index 76c5bcb745..2ab15a6921 100644
--- a/doc/x3/quick_reference.qbk
+++ b/doc/x3/quick_reference.qbk
@@ -298,7 +298,7 @@ a: vector, b: vector --> (a > b): vector``]]
[[__x3_alternative__ (`a | b`)]
[``a: A, b: B --> (a | b): variant
a: A, b: Unused --> (a | b): optional
-a: A, b: B, c: Unused --> (a | b | c): optional >
+a: A, b: B, c: Unused --> (a | b | c): variant
a: Unused, b: B --> (a | b): optional
a: Unused, b: Unused --> (a | b): Unused
a: A, b: A --> (a | b): A``]]
diff --git a/include/boost/spirit/home/x3/operator/alternative.hpp b/include/boost/spirit/home/x3/operator/alternative.hpp
index aeb6998ba4..8d3ef26612 100644
--- a/include/boost/spirit/home/x3/operator/alternative.hpp
+++ b/include/boost/spirit/home/x3/operator/alternative.hpp
@@ -7,12 +7,13 @@
#if !defined(BOOST_SPIRIT_X3_ALTERNATIVE_JAN_07_2013_1131AM)
#define BOOST_SPIRIT_X3_ALTERNATIVE_JAN_07_2013_1131AM
-#include
#include
#include
-
+#include
#include
+#include
+
namespace boost { namespace spirit { namespace x3
{
template
@@ -53,11 +54,96 @@ namespace boost { namespace spirit { namespace x3
}
}}}
+
+namespace boost { namespace spirit { namespace x3 { namespace detail
+{
+ template
+ struct add_alternative_types_impl;
+
+ template typename Seq, typename... Ts>
+ struct add_alternative_types_impl>
+ {
+ using type = Seq;
+ };
+
+ template typename Seq, typename... Ts, typename U, typename... Us>
+ struct add_alternative_types_impl, U, Us...>
+ {
+ using next_sequence = conditional_t::template contains,
+ Seq,
+ conditional_t, unused_type>,
+ typename Seq::template prepend,
+ typename Seq::template append
+ >
+ >;
+
+ using type = typename add_alternative_types_impl::type;
+ };
+
+ template
+ using add_alternative_types = typename add_alternative_types_impl::type;
+
+ template
+ struct merge_types_of_alternative_impl;
+
+ template typename Seq1, typename... T1s, template typename Seq2, typename... T2s>
+ struct merge_types_of_alternative_impl, Seq2>
+ {
+ using type = add_alternative_types, T2s...>;
+ };
+
+ template
+ using merge_types_of_alternative = typename merge_types_of_alternative_impl::type;
+
+ template
+ struct get_types_of_alternative
+ {
+ using type = type_sequence::type>;
+ };
+
+ template
+ struct get_types_of_alternative, C>
+ {
+ using type = merge_types_of_alternative<
+ typename get_types_of_alternative::type,
+ typename get_types_of_alternative::type
+ >;
+ };
+
+ template typename A, typename Seq>
+ struct type_sequence_to_alternative_attribute;
+
+ template typename A, template typename Seq>
+ struct type_sequence_to_alternative_attribute>
+ {
+ using type = unused_type;
+ };
+
+ template typename A, template typename Seq, typename T, typename... Ts>
+ struct type_sequence_to_alternative_attribute>
+ {
+ using type = conditional_t
+ >;
+ };
+
+ template typename A, template typename Seq, typename T>
+ struct type_sequence_to_alternative_attribute>
+ {
+ using type = boost::optional;
+ };
+
+ template class A, typename P, typename C>
+ using attribute_of_alternative = type_sequence_to_alternative_attribute::type>;
+}}}}
+
namespace boost { namespace spirit { namespace x3 { namespace traits
{
template
struct attribute_of, Context>
- : x3::detail::attribute_of_binary {};
+ : x3::detail::attribute_of_alternative, Context> {};
}}}}
#endif
diff --git a/include/boost/spirit/home/x3/operator/sequence.hpp b/include/boost/spirit/home/x3/operator/sequence.hpp
index 9e6e1702fc..3edbfbfd92 100644
--- a/include/boost/spirit/home/x3/operator/sequence.hpp
+++ b/include/boost/spirit/home/x3/operator/sequence.hpp
@@ -7,10 +7,11 @@
#if !defined(BOOST_SPIRIT_X3_SEQUENCE_JAN_06_2013_1015AM)
#define BOOST_SPIRIT_X3_SEQUENCE_JAN_06_2013_1015AM
-#include
#include
#include
#include
+#include
+#include
#include
@@ -64,11 +65,40 @@ namespace boost { namespace spirit { namespace x3
}
}}}
+namespace boost { namespace spirit { namespace x3 { namespace detail
+{
+ template
+ struct types_of_sequence_init : type_sequence {};
+ template <>
+ struct types_of_sequence_init : type_sequence<> {};
+ template <>
+ struct types_of_sequence_init : type_sequence<> {};
+
+ template
+ struct get_types_of_sequence
+ : types_of_sequence_init::type> {};
+
+ template
+ struct get_types_of_sequence, C>
+ : get_types_of_sequence::template extend> {};
+
+ template class A, typename T, int = T::size>
+ struct type_sequence_to_attribute { using type = typename T::template transfer_to; };
+ template class A, typename T>
+ struct type_sequence_to_attribute : T::template transfer_to {};
+ template class A, typename T>
+ struct type_sequence_to_attribute { using type = unused_type; };
+
+ template class A, typename P, typename C>
+ using attribute_of_sequence = type_sequence_to_attribute::type>;
+}}}}
+
namespace boost { namespace spirit { namespace x3 { namespace traits
{
template
struct attribute_of, Context>
- : x3::detail::attribute_of_binary {};
+ : x3::detail::attribute_of_sequence, Context> {};
}}}}
#endif
diff --git a/include/boost/spirit/home/x3/support/meta.hpp b/include/boost/spirit/home/x3/support/meta.hpp
new file mode 100644
index 0000000000..aed1a18d6b
--- /dev/null
+++ b/include/boost/spirit/home/x3/support/meta.hpp
@@ -0,0 +1,57 @@
+/*=============================================================================
+ Copyright (c) 2020 Nikita Kniazev
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+
+#ifndef BOOST_SPIRIT_X3_SUPPORT_META
+#define BOOST_SPIRIT_X3_SUPPORT_META
+
+#include
+#include
+
+namespace boost { namespace spirit { namespace x3 { namespace detail
+{
+ template
+ struct type_sequence
+ {
+ using type = type_sequence;
+
+ static const int size = sizeof...(T);
+
+ template
+ using append = type_sequence;
+
+ template
+ using prepend = type_sequence;
+
+ template
+ using extend = typename U::template prepend;
+
+ template class U>
+ using transfer_to = U;
+
+ template
+ static constexpr bool contains = (std::is_same_v || ...);
+ };
+
+ template
+ struct conditional_impl
+ {
+ template
+ using type = T;
+ };
+
+ template <>
+ struct conditional_impl
+ {
+ template
+ using type = F;
+ };
+
+ template
+ using conditional_t = typename conditional_impl::template type;
+}}}}
+
+#endif
diff --git a/include/boost/spirit/home/x3/support/traits/attribute_of_binary.hpp b/include/boost/spirit/home/x3/support/traits/attribute_of_binary.hpp
deleted file mode 100644
index 2cbada00bb..0000000000
--- a/include/boost/spirit/home/x3/support/traits/attribute_of_binary.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*=============================================================================
- Copyright (c) 2020 Nikita Kniazev
-
- Distributed under the Boost Software License, Version 1.0. (See accompanying
- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-=============================================================================*/
-#ifndef BOOST_SPIRIT_X3_SUPPORT_TRAITS_ATTRIBUTE_OF_BINARY
-#define BOOST_SPIRIT_X3_SUPPORT_TRAITS_ATTRIBUTE_OF_BINARY
-
-#include
-#include
-#include
-
-namespace boost { namespace spirit { namespace x3 { namespace detail
-{
- template
- struct type_sequence
- {
- using type = type_sequence;
-
- static const int size = sizeof...(T);
-
- template
- using append = type_sequence;
-
- template
- using prepend = type_sequence;
-
- template
- using extend = typename U::template prepend;
-
- template class U>
- using transfer_to = U;
- };
-
- template
- struct types_of_binary_init : type_sequence {};
- template <>
- struct types_of_binary_init : type_sequence<> {};
- template <>
- struct types_of_binary_init : type_sequence<> {};
-
- template class B, typename P, typename C>
- struct get_types_of_binary
- : types_of_binary_init::type> {};
- template class B, typename L, typename R, typename C>
- struct get_types_of_binary, C>
- : get_types_of_binary::template extend> {};
-
- template class A, typename T, int = T::size>
- struct type_sequence_to_attribute { using type = typename T::template transfer_to; };
- template class A, typename T>
- struct type_sequence_to_attribute : T::template transfer_to {};
- template class A, typename T>
- struct type_sequence_to_attribute { using type = unused_type; };
-
- template class A, template class B,
- typename L, typename R, typename C>
- using attribute_of_binary = type_sequence_to_attribute, C>::type>;
-}}}}
-#endif
diff --git a/test/x3/Jamfile b/test/x3/Jamfile
index f2671e6ba1..e03ec50170 100644
--- a/test/x3/Jamfile
+++ b/test/x3/Jamfile
@@ -32,6 +32,7 @@ project spirit-x3
cxx14_return_type_deduction # grep -Er "auto[^\\(=\\)]+\(" *
#cxx14_std_exchange # grep -r "exchange" *
cxx14_variable_templates
+ cxx17_fold_expressions
]
;
diff --git a/test/x3/alternative.cpp b/test/x3/alternative.cpp
index 6a1a63388d..be1af4faf1 100644
--- a/test/x3/alternative.cpp
+++ b/test/x3/alternative.cpp
@@ -45,6 +45,14 @@ struct stationary : boost::noncopyable
int val;
};
+template
+constexpr void test_attribute_of_alternative(Expr)
+{
+ using namespace boost::spirit::x3;
+ using namespace boost::spirit::x3::traits;
+
+ static_assert(std::is_same_v::type>);
+}
int
main()
@@ -296,5 +304,25 @@ main()
BOOST_TEST(test_attr("abaabb", +('a' >> attr(Foo{}) | 'b' >> attr(int{})), x));
}
+ { // compile checks
+ using namespace boost::spirit::x3;
+
+ test_attribute_of_alternative>(char_ | int_);
+ test_attribute_of_alternative>(char_ | int_ | double_);
+ test_attribute_of_alternative>(char_ | int_ | double_ | eps);
+ test_attribute_of_alternative>(char_ | int_ | double_ | eps | int_);
+ test_attribute_of_alternative>(char_ | int_ | double_ | eps | int_ | eps);
+ test_attribute_of_alternative(eps);
+ test_attribute_of_alternative>(eps | int_);
+ test_attribute_of_alternative>(eps | int_);
+ test_attribute_of_alternative(eps | eps);
+ test_attribute_of_alternative(int_ | int_);
+ test_attribute_of_alternative(int_);
+
+ test_attribute_of_alternative, char>>((int_ >> int_) | char_);
+ test_attribute_of_alternative>>(char_ | (int_ >> int_) | eps);
+ test_attribute_of_alternative>>(eps | (int_ >> int_));
+ }
+
return boost::report_errors();
}
diff --git a/test/x3/sequence.cpp b/test/x3/sequence.cpp
index 2b94dfa8aa..8948122a23 100644
--- a/test/x3/sequence.cpp
+++ b/test/x3/sequence.cpp
@@ -15,6 +15,15 @@
#include "test.hpp"
#include "utils.hpp"
+template
+void test_attribute_of_sequence(Expr)
+{
+ using namespace boost::spirit::x3;
+ using namespace boost::spirit::x3::traits;
+
+ static_assert(std::is_same_v::type>);
+}
+
int
main()
{
@@ -493,5 +502,16 @@ main()
BOOST_TEST_EQ(v.size(), 4);
}
+ { // compile checks only
+ using namespace boost::spirit::x3;
+
+ test_attribute_of_sequence>(int_ >> int_);
+ test_attribute_of_sequence(int_ >> eps);
+ test_attribute_of_sequence(eps >> int_);
+ test_attribute_of_sequence(eps >> eps);
+ test_attribute_of_sequence(eps >> int_ >> eps);
+ test_attribute_of_sequence>(int_ >> eps >> eps >> int_ >> eps);
+ }
+
return boost::report_errors();
}