Open Bockeman opened 2 years ago
Don't know variant or single element tuple or both, but not x3::symbols:
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace ast {
struct tagged_token { int token; };
}
BOOST_FUSION_ADAPT_STRUCT(ast::tagged_token, token)
int main() {
namespace x3 = boost::spirit::x3;
char const* iter = "/** /**/", * const end = iter + std::strlen(iter);
x3::variant<ast::tagged_token> x;
x3::parse(iter, end, x3::attr(int{}), x);
}
It seems that not the single element variant is the problem. It depends on the number of struct/class members. No member works, two or more members works but not one member:
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <variant>
struct no_member {};
struct one_member {
int a;
};
BOOST_FUSION_ADAPT_STRUCT(one_member, a)
struct two_members {
int a{};
int b{};
};
BOOST_FUSION_ADAPT_STRUCT(two_members, a, b)
int main()
{
namespace x3 = boost::spirit::x3;
char const* iter = "", * const end = iter + std::strlen(iter);
std::variant<no_member, one_member, two_members> x;
x3::parse(iter, end, x3::attr(no_member{}), x); // This line compiles
x3::parse(iter, end, x3::attr(one_member{}), x); // This line failes
x3::parse(iter, end, x3::attr(two_members{}), x); // This line compiles
}
Is there a workaround available for this behaviour?
Use boost::variant instead of std::variant.
The problem, I'd guess, is:
https://www.boost.org/doc/libs/1_81_0/boost/spirit/home/x3/support/traits/is_variant.hpp
doesn't consider std::variant as a variant.
OOPS! Adding obvious change to is_variant.hpp not enough. With the obvious change, now getting, using std::variant:
C:/msys64/home/evansl/prog_dev/boost.org/1_80_0download/download/boost/spirit/home/x3/support/traits/variant_has_substitute.hpp:23:40: error: no type named 'types' in 'std::variant<no_member, one_member, two_members>'
typedef typename variant_type::types types;
~~~~~~~~~~~~~~~~~~~~~~~^~~~~
OOPS! Adding obvious change to is_variant.hpp not enough. With the obvious change, now getting, using std::variant:
C:/msys64/home/evansl/prog_dev/boost.org/1_80_0download/download/boost/spirit/home/x3/support/traits/variant_has_substitute.hpp:23:40: error: no type named 'types' in 'std::variant<no_member, one_member, two_members>' typedef typename variant_type::types types; ~~~~~~~~~~~~~~~~~~~~~~~^~~~~
However, changing obvious portion of variant_has_substitute.hpp to:
template <typename Variant, typename T>
struct variant_has_substitute_impl
;
template <template<typename...>typename Variant, typename T, typename... Elements>
struct variant_has_substitute_impl< Variant<Elements...>, T>
{
// Find a type from the Variant that can be a substitute for T.
// return true_ if one is found, else false_
typedef Variant<Elements...> variant_type;
typedef fusion::vector<Elements...> types;
and #including <boost/fusion/container.hpp> before seems to solve problem.
@cppljevans Thank you for your response. Replacing std::variant
with boost::variant
(or x3::variant
) did the trick!
Sorry for confusing with the original post of @Bockeman.
This code does not compile
It seems the only way to successfully compile is to wrap the token (
x3::symbols<>
) into a rule (either inline, or with a separate rule definition). Is this an X3 implementation problem, or is it beyond the anticipated capabilities of X3?