I have the following test that works fine in a test app but in my big code it doesn't compile. What happens is that the parser is trying to hand me Char
instead of a std::string
. I've looked for any possible reason I would get different result, but, to no avail. Here is the code that works. Thanks to sehe for the std::variant
adapter. here
and here
#include <iostream>
#include <unordered_map>
#include <variant>
#include <string>
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
using rpn_val = std::variant<std::monostate, int64_t, std::wstring, double>;
std::ostream& operator << (std::ostream& os, const std::monostate& rp) { return os << "NULL"; }
struct rpn_val_print_ostream {
std::ostream& os;
rpn_val_print_ostream(std::ostream& os) : os(os) {}
void operator()(const std::monostate& item) { os << " NULL "; }
void operator()(const int64_t& item) { os << " int: " << std::dec << item; }
void operator()(const std::wstring& item) { os << " str: "; }
void operator()(const double& item) { os << " double: " << item; }
};
std::ostream& operator << (std::ostream& os, const rpn_val& rp) { std::visit(rpn_val_print_ostream(os), rp); return os; }
namespace boost::spirit::x3::traits {
template<typename... T>
struct is_variant<std::variant<T...> >
: mpl::true_ {};
template <typename Attribute, typename... T>
struct variant_has_substitute_impl<std::variant<T...>, Attribute>
{
typedef std::variant<T...> variant_type;
typedef typename mpl::transform<
mpl::list<T...>
, unwrap_recursive<mpl::_1>
>::type types;
typedef typename mpl::end<types>::type end;
typedef typename mpl::find<types, Attribute>::type iter_1;
typedef typename
mpl::eval_if<
is_same<iter_1, end>,
mpl::find_if<types, traits::is_substitute<mpl::_1, Attribute>>,
mpl::identity<iter_1>
>::type
iter;
typedef mpl::not_<is_same<iter, end>> type;
};
template <typename Attribute, typename... T>
struct variant_find_substitute<std::variant<T...>, Attribute>
{
typedef std::variant<T...> variant_type;
typedef typename mpl::transform<
mpl::list<T...>
, unwrap_recursive<mpl::_1>
>::type types;
typedef typename mpl::end<types>::type end;
typedef typename mpl::find<types, Attribute>::type iter_1;
typedef typename
mpl::eval_if<
is_same<iter_1, end>,
mpl::find_if<types, traits::is_substitute<mpl::_1, Attribute> >,
mpl::identity<iter_1>
>::type
iter;
typedef typename
mpl::eval_if<
is_same<iter, end>,
mpl::identity<Attribute>,
mpl::deref<iter>
>::type
type;
};
template <typename... T>
struct variant_find_substitute<std::variant<T...>, std::variant<T...> >
: mpl::identity<std::variant<T...> > {};
#if defined(BOOST_SPIRIT_X3_DEBUG)
template <typename Out, typename... Ts>
struct print_attribute_debug<Out, std::variant<Ts...>, void> {
template <typename V>
static void call(Out& out, V const& value) {
std::visit([&out](auto const& v) {
x3::traits::print_attribute(out, v);
}, value);
}
};
#endif
}
namespace x3 = boost::spirit::x3;
template <typename T>
struct as_type {
template <typename Expr>
auto operator[](Expr&& expr) const {
return x3::rule<class _, T>{"as"} = x3::as_parser(std::forward<Expr>(expr));
}
};
template <typename T> static const as_type<T> as = {};
template <>
void x3::traits::detail::move_to<std::string, rpn_val>(std::string& src, rpn_val& dest, variant_attribute, mpl::false_)
{
//TODO move from string to wstring;
}
const auto quoted_string = x3::lit('"') > x3::lexeme[*((x3::alnum | '_') - '"')] > '"';
const auto int_rule = x3::int64 >> !x3::lit(".");
const auto variant_str_parser = as<std::string>[quoted_string];
//const auto variant_parser = int_rule | x3::double_ | variant_str_parser;
const auto variant_parser = int_rule | x3::double_ | quoted_string;
const auto variable_parser = (x3::lexeme[+x3::char_("a-zA-Z0-9")] >> variant_parser) % ";";
int main() {
std::string input = R"( name "dan"; double 4.5; intx 9;
nameb "mane";
)";
auto first = input.begin();
std::unordered_map<std::string, rpn_val> map;
auto r = x3::phrase_parse(first, input.end(), variable_parser, x3::space, map);
for (auto& item : map) {
std::cout << item.first << "\t " << item.second << std::endl;
}
return 0;
}
With a breakpoint in the specialized move_to
, I'm clearly being handed a std::string&
in the test app. In my big app, I get a compiler error the likes of:
1>...\x3\support\traits\move_to.hpp(62,1): error C2679: binary '=': no operator found which takes a right-hand operand of type 'char' (or there is no acceptable conversion) (compiling source file rpt_parse.cpp)
1>...\x3\support\traits\move_to.hpp(62,1): message : while trying to match the argument list '(Dest, char)'
1> with
1> [
1> Dest=value_type
1> ] (compiling source file rpt_parse.cpp)
1>...\x3\support\traits\move_to.hpp(81): message : see reference to function template instantiation 'void boost::spirit::x3::traits::detail::move_to_plain<Source,Dest>(Source &,Dest &,boost::mpl::false_)' being compiled
1> with
1> [
1> Source=char,
1> Dest=value_type
1> ] (compiling source file rpt_parse.cpp)
1>...\x3\support\traits\move_to.hpp(196): message : see reference to function template instantiation 'void boost::spirit::x3::traits::detail::move_to<char,Dest>(Source &,Dest &,boost::spirit::x3::traits::plain_attribute)' being compiled
1> with
1> [
1> Dest=value_type,
1> Source=char
1> ] (compiling source file rpt_parse.cpp)
1>...\x3\char\char_parser.hpp(31): message : see reference to function template instantiation 'void boost::spirit::x3::traits::move_to<char&,Attribute>(Source,Dest &)' being compiled
1> with
1> [
1> Attribute=value_type,
1> Source=char &,
1> Dest=value_type
1> ] (compiling source file rpt_parse.cpp)
1>...\x3\core\detail\parse_into_container.hpp(97): message : see reference to function template instantiation 'bool boost::spirit::x3::char_parser<boost::spirit::x3::char_set<Encoding,boost::spirit::char_encoding::standard::char_type>>::parse<Iterator,Context,value_type>(Iterator &,const Iterator &,const Context &,boost::spirit::x3::unused_type,Attribute &) const' being compiled
1> with
1> [
1> Encoding=boost::spirit::char_encoding::standard,
1> Iterator=std::_String_iterator<std::_String_val<std::_Simple_types<char>>>,
1> Context=boost::spirit::x3::context<boost::spirit::x3::skipper_tag,unused_skipper_type,boost::spirit::x3::context<boost::spirit::x3::skipper_tag,const boost::spirit::x3::standard::space_type,boost::spirit::x3::unused_type>>,
1> Attribute=value_type
1> ] (compiling source file rpt_parse.cpp)
I've even gone so far as to paste this code into a function, with the parsers, well outside of my parser namespaces and I still get the error. Something subtle, but I can't figure...