Boost Spirit compilation error "error_invalid_expression" - c++

I am trying to figure out what is wrong with this Boost Spirit code:
#include <iostream>
#include <string>
#include <boost/spirit/include/qi_uint.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
template <typename Iterator>
struct Header
{
struct Type : boost::fusion::vector2<unsigned int, unsigned int>
{
unsigned int getFirstThing() { return boost::fusion::at_c<0>(*this); }
unsigned int getSecondThing() { return boost::fusion::at_c<1>(*this); }
};
};
template<typename Iterator>
struct HeaderParse
: boost::spirit::qi::grammar<Iterator, typename Header<Iterator>::Type() >
{
HeaderParse()
: HeaderParse::base_type(_start)
{
using boost::spirit::qi::uint_parser;
_start = '<'
>> uint_parser<unsigned int, 10, 1, 3>()
>> '>'
>> uint_parser<unsigned int, 10, 1, 3>();
_start.name("HeaderParse");
}
~HeaderParse() = default;
boost::spirit::qi::rule<Iterator, typename Header<Iterator>::Type() > _start;
};
int main()
{
const std::string d1 = "<1>2";
const HeaderParse<std::string::const_iterator> parser;
Header<std::string::const_iterator>::Type header;
std::string::const_iterator begin = d1.begin();
std::string::const_iterator end = d1.end();
assert(boost::spirit::qi::parse(begin, end, parser, header));
return 0;
}
This is the compilation error that I see when I try to compile:
$ make --jobs=8
Scanning dependencies of target testapp
[ 50%] Building CXX object CMakeFiles/testapp.dir/test.cpp.o
In file included from /Users/addy/nw/stub/test.cpp:5:
In file included from /Users/addy/Downloads/boost_1_65_1/boost/spirit/include/qi_grammar.hpp:16:
In file included from /Users/addy/Downloads/boost_1_65_1/boost/spirit/home/qi/nonterminal/grammar.hpp:18:
/Users/addy/Downloads/boost_1_65_1/boost/spirit/home/qi/nonterminal/rule.hpp:177:13: error: static_assert failed "error_invalid_expression"
BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
/Users/aclaure/nw/stub/test.cpp:27:16: note: in instantiation of function template specialization 'boost::spirit::qi::rule<std::__1::__wrap_iter<const char *>,
Header<std::__1::__wrap_iter<const char *> >::Type (), boost::spirit::unused_type, boost::spirit::unused_type,
boost::spirit::unused_type>::operator=<boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right, boost::proto::argsns_::list2<const
boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right,
boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right, boost::proto::argsns_::list2<const
boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::terminal_ex<boost::spirit::tag::lit, boost::fusion::vector<char
const (&)[7]> > >, 0> &, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<const char &>, 0> >, 2> &, const
boost::spirit::qi::uint_parser<unsigned int, 10, 1, 3> &>, 2> &, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<const char &>, 0>
>, 2> &, const boost::spirit::qi::uint_parser<unsigned int, 10, 1, 3> &>, 2> >' requested here
_start =
^
/Users/aclaure/nw/stub/test.cpp:46:52: note: in instantiation of member function 'HeaderParse<std::__1::__wrap_iter<const char *> >::HeaderParse' requested here
const HeaderParse<std::string::const_iterator> parser;
Which leads me to this comment in the Spirit header files:
// Report invalid expression error as early as possible.
// If you got an error_invalid_expression error message here,
// then the expression (expr) is not a valid spirit qi expression.
But the expression I have written seems valid to me. I am not sure what could be wrong with it. Any help is much appreciated!

You're missing a header. I can't say which one but if I just include
#include <boost/spirit/home/qi.hpp>
it compiles.
Live example on Wandbox
N.B.: I couldn't find any “official” statement but I don't think including the individual headers is recommended. At least none of the Qi examples does it.
I guess you only include those headers because you hope to reduce compile-time that way. If you really want to speed things up, consider using X3 instead. This example takes about 1 sec to compile on my machine.
#include <iostream>
#include <string>
#include <tuple>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted.hpp>
namespace Header {
using Type = std::tuple<unsigned int, unsigned int>;
namespace x3 = boost::spirit::x3;
x3::uint_parser<unsigned int, 10, 1, 3> uint_;
x3::rule<class parser, Type> const parser = "parser";
auto const parser_def = '<' >> uint_ >> '>' >> uint_;
BOOST_SPIRIT_DEFINE(parser)
}
int main()
{
const std::string d1 = "<1>2";
Header::Type header;
auto iter = d1.begin();
auto end = d1.end();
bool r = boost::spirit::x3::parse(iter, end, Header::parser, header);
if (!r || iter != end) {
std::cerr << "Parsing failed at " << std::string{iter,end} << "\n";
} else {
std::cout << std::get<0>(header) << " " << std::get<1>(header) << "\n";
}
}
Live example on Wandbox

Related

boost::make_recursive_variant has no member named 'apply_visitor'

First time using Boost, and trying to grok how to use boost::variant. Please find below an example program and the error message (GCC v5.3.0, -std=c++14)
#include <vector>
#include <iostream>
#include <sstream>
#include <boost/variant.hpp>
using int_tree_t =
boost::make_recursive_variant <
int,
std::vector<boost::recursive_variant_>>;
auto operator << (std::ostream& out, const int_tree_t& tree) ->
std::ostream&
{
struct stringify :
public boost::static_visitor <std::string>
{
public:
auto operator () (int i) const ->
std::string
{
return std::to_string (i);
}
auto operator () (const std::vector<int_tree_t>& vec) const ->
std::string
{
std::stringstream ss;
ss << "(";
auto it = std::begin (vec);
if (!vec.empty ()) {
ss << *it;
}
for (; it != std::end (vec); ++it) {
ss << " " << *it;
}
ss << ")";
return ss.str ();
}
};
std::stringstream ss;
ss.flags (out.flags ());
ss << boost::apply_visitor (stringify (), tree);
return (out << ss.str ());
}
Error message:
In file included from /usr/local/include/boost/variant/apply_visitor.hpp:16:0,
from /usr/local/include/boost/variant/detail/hash_variant.hpp:23,
from /usr/local/include/boost/variant/variant.hpp:34,
from /usr/local/include/boost/variant.hpp:17,
from test2.cpp:5:
/usr/local/include/boost/variant/detail/apply_visitor_unary.hpp: In instantiation of ‘typename Visitor::result_type boost::apply_visitor(const Visitor&, Visitable&) [with Visitor = operator<<(std::ostream&, const int_tree_t&)::stringify; Visitable = const boost::make_recursive_variant<int, std::vector<boost::recursive_variant_, std::allocator<boost::recursive_variant_> > >; typename Visitor::result_type = std::__cxx11::basic_string<char>]’:
test2.cpp:50:43: required from here
/usr/local/include/boost/variant/detail/apply_visitor_unary.hpp:84:43: error: ‘const struct boost::make_recursive_variant<int, std::vector<boost::recursive_variant_, std::allocator<boost::recursive_variant_> > >’ has no member named ‘apply_visitor’
return visitable.apply_visitor(visitor);
^
If I understand correctly, boost::make_recursive_variant is supposed to create a type which acts identical to boost::variant... but the error message appears to indicate that it doesn't have the apply_visitor function, which is necessary for visitation. I've read over [this(http://www.boost.org/doc/libs/1_60_0/doc/html/variant/tutorial.html) page, but there's nothing there about having to use a "special" visitation pattern with recursive variants.
How should I be writing this program?
make_recursive_variant is a metafunction, not a type in its own right. So you have to evaluate the metafunction:
using int_tree_t =
boost::make_recursive_variant <
int,
std::vector<boost::recursive_variant_>>::type;
↑↑↑↑↑↑
Otherwise, you're using a metafunction type instead of a variant type.

Parse to struct with default value

My AST node is struct
struct node_type
{
type::code type_id;
boost::variant<int, std::string> value;
};
Adapter and grammar:
BOOST_FUSION_ADAPT_STRUCT(
client::node_type,
(client::type::code, id)
(boost::variant<int, std::string>, value)
)
namespace client
{
struct or_op
{
node_type left, right;
};
namespace type
{
enum code{NUMBER, STRING, BOOL};
}
// Grammar
template <typename Iterator>
struct pair_grammar : qi::grammar<
Iterator,
node_type(), // Grammar generates node_type
ascii::space_type
>
{
pair_grammar() : pair_grammar::base_type(
expr // main 'rule'
)
{
using qi::lit;
using qi::lexeme;
using ascii::char_;
using qi::int_;
using ascii::string;
using namespace qi::labels;
using phoenix::at_c;
using phoenix::push_back;
expr = int_[at_c<0>(qi::_val) = 0, at_c<1>(qi::_val) = qi::_1];
}
qi::rule<Iterator, node_type(), ascii::space_type> expr;
};
}
The code above doesn't compile. First of all i get warning
error: macro "BOOST_FUSION_ADAPT_STRUCT_FILLER_0" passed 3 arguments, but takes just 2
and then a lot of errors, starting with
qi/nonterminal/rule.hpp:303:17: error: no match for call to '(const function_type {aka const boost::function<bool(const char*&, const char* const&, boost::spirit::context<boost::fusion::cons<client::node_type&, boost::fusion::nil>, boost::fusion::vector0<> >&, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&)>}) (const char*&, const char* const&, boost::spirit::qi::rule<const char*, client::node_type(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type>::context_type&, const boost::spirit::unused_type&)'
What am I doing wrong? Thanks.
EDIT:
Macro warning appeared because of ',' in macro. Typedef solved problem
typedef boost::variant<int, std::string> node_value_t;
struct node_type
{
type::code type_id;
node_value_t value;
};
BOOST_FUSION_ADAPT_STRUCT(
client::node_type,
(client::type::code, type_id)
(client::node_value_t, value)
)
But code still doesn't compile. I also tried
number = int_[qi::_val = phoenix::construct<node_type>(type::NUMBER, qi::_1)];
But that didnt help.
EDIT 2: Simplified original rule. Still no success.
A number of issues here.
The message
error: macro "BOOST_FUSION_ADAPT_STRUCT_FILLER_0" passed 3 arguments, but takes just 2
occurs because of the , in the template arguments for variant<>. You can fix it using a typedef:
namespace client {
namespace type { enum code{NUMBER, STRING, BOOL}; }
struct node_type {
type::code type_id;
typedef boost::variant<int, std::string> vt_type;
vt_type value;
};
}
BOOST_FUSION_ADAPT_STRUCT(
client::node_type,
(client::type::code, type_id)
(client::node_type::vt_type, value)
)
You were assigning an int to the attribute of enum type. The implicit conversion is not allowed. Instead, supply the required enum type:
expr = int_ [at_c<0>(qi::_val) = client::type::NUMBER, at_c<1>(qi::_val) = qi::_1];
At this point, everything compiles and works: Live On Coliru
using namespace client;
pair_grammar<std::string::const_iterator> grammar;
std::string const input = "123";
auto f(input.begin()), l(input.end());
node_type node;
bool ok = qi::phrase_parse(f, l, grammar, ascii::space, node);
assert(ok);
assert(f == l);
assert(node.type_id == type::NUMBER);
assert(node.value == node_type::vt_type(123));
I don't think this solution is optimal, though.
Consider using the Spirit directives where possible, and staying away from Semantic actions that uglify the grammar, are a frequent source of errors/UB, make compile times even longer... [1]:
pair_grammar() : pair_grammar::base_type(expr)
{
expr = qi::attr(client::type::NUMBER) >> qi::int_;
}
See that Live On Coliru too:
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = qi::ascii;
namespace client
{
namespace type
{
enum code{NUMBER, STRING, BOOL};
}
struct node_type
{
type::code type_id;
typedef boost::variant<int, std::string> vt_type;
vt_type value;
};
}
/*Adapter and grammar:*/
BOOST_FUSION_ADAPT_STRUCT(
client::node_type,
(client::type::code, type_id)
(client::node_type::vt_type, value)
)
namespace client
{
struct or_op
{
node_type left, right;
};
// Grammar
template <typename Iterator>
struct pair_grammar : qi::grammar<
Iterator,
node_type(), // Grammar generates node_type
ascii::space_type
>
{
pair_grammar() : pair_grammar::base_type(expr)
{
expr = qi::attr(client::type::NUMBER) >> qi::int_;
}
qi::rule<Iterator, node_type(), ascii::space_type> expr;
};
}
int main()
{
using namespace client;
pair_grammar<std::string::const_iterator> grammar;
std::string const input = "123";
auto f(input.begin()), l(input.end());
node_type node;
bool ok = qi::phrase_parse(f, l, grammar, ascii::space, node);
assert(ok);
assert(f == l);
assert(node.type_id == type::NUMBER);
assert(node.value == node_type::vt_type(123));
}
[1] Boost Spirit: "Semantic actions are evil"?

Filter the synthesized attribute through a std::map in a boost spirit semantic action

I have a case where I'd like to filter the value that comes up as a synthesized attribute inside of a rule through a std::map.
The map is pre-generated and will not change during the parsing.
The nature of the map and the real parser means that the lookup should never fail (although the actual number of elements may be quite large)
The usual approach perfectly suited to this problem (use a symbol table) isn't appropriate for the real case. In the real problem, the lookup is conditional based on an attribute that won't be apparent until much later in the parse (in a somewhat removed rule).
My attempt:
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/foreach.hpp>
#include <string>
#include <iostream>
#include <vector>
#include <map>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
int main() {
std::map<unsigned int, unsigned int> myMap;
myMap[1] = 100; myMap[2] = 200; myMap[3] = 300;
std::string test = "1 2 3";
std::vector<unsigned int> results;
qi::rule<std::string::iterator, unsigned int()> r
= qi::uint_ [qi::_val = phx::at(myMap, qi::_1)];
qi::parse(test.begin(), test.end(), ( r % " " ), results);
BOOST_FOREACH(unsigned int &x, results) {
std::cout << x << "\n";
}
}
I guess I was under the impression, due to the phoenix support for stl containers, that this should work. But I get a compile error on the rule line. This error goes away if I replace the semantic action with the classic pointless [qi::_val = qi::_1] (not surprisingly).
The compiler error under MSVS10 is shockingly long, as usual, but here's the first mention of my code file: (at C:\code\Compiler2\spirit_test.cpp(25)... line 25 is the rule r)
C:\boost_1_50_0\boost/spirit/home/qi/nonterminal/rule.hpp(191) : see reference to function template instantiatio
n 'void boost::spirit::qi::rule<Iterator,T1>::define<boost::mpl::false_,Expr>(boost::spirit::qi::rule<Iterator,T1> &,con
st Expr &,boost::mpl::true_)' being compiled
with
[
Iterator=std::_String_iterator<char,std::char_traits<char>,std::allocator<char>>,
T1=unsigned int (void),
Expr=boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript,boost::proto::argsns_::list2<const boo
st::spirit::terminal<boost::spirit::tag::uint_> &,const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::p
roto::tagns_::tag::assign,boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,b
oost::proto::argsns_::term<boost::spirit::attribute<0>>,0>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost
::phoenix::detail::tag::function_eval,boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns
_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::stl::at_impl>,0>,boost::phoenix::actor<boost::proto::exprns
_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::reference_wrapper<std::map<unsigned
int,unsigned int>>>,0>>,boost::phoenix::actor<boost::spirit::argument<0>>>,3>>>,2>> &>,2>
]
C:\code\Compiler2\spirit_test.cpp(25) : see reference to function template instantiation 'boost::spirit::qi
::rule<Iterator,T1>::rule<boost::proto::exprns_::expr<Tag,Args,Arity>>(const Expr &,const std::string &)' being compiled
with
[
Iterator=std::_String_iterator<char,std::char_traits<char>,std::allocator<char>>,
T1=unsigned int (void),
Tag=boost::proto::tagns_::tag::subscript,
Args=boost::proto::argsns_::list2<const boost::spirit::terminal<boost::spirit::tag::uint_> &,const boost::ph
oenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign,boost::proto::argsns_::list2<boost::pro
to::exprns_::expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::spirit::attribute<0>>,0>,boost:
:phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval,boost::proto::argsns_::list
3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::stl:
:at_impl>,0>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::a
rgsns_::term<boost::reference_wrapper<std::map<unsigned int,unsigned int>>>,0>>,boost::phoenix::actor<boost::spirit::arg
ument<0>>>,3>>>,2>> &>,
Arity=2,
Expr=boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript,boost::proto::argsns_::list2<const boo
st::spirit::terminal<boost::spirit::tag::uint_> &,const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::p
roto::tagns_::tag::assign,boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,b
oost::proto::argsns_::term<boost::spirit::attribute<0>>,0>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost
::phoenix::detail::tag::function_eval,boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns
_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::stl::at_impl>,0>,boost::phoenix::actor<boost::proto::exprns
_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::reference_wrapper<std::map<unsigned
int,unsigned int>>>,0>>,boost::phoenix::actor<boost::spirit::argument<0>>>,3>>>,2>> &>,2>
]
C:\boost_1_50_0\boost/proto/transform/default.hpp(154) : error C2440: '=' : cannot convert from 'std::pair<_Ty1,_Ty2>' t
o 'unsigned int'
with
[
_Ty1=const unsigned int,
_Ty2=unsigned int
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Reposting from comment
Try qi::_val = phx::ref(myMap)[qi::_1] rather than qi::_val = phx::at(myMap, qi::_1).
The problem is that the return type of phoenix::at is defined in this header as container::value_type. This is a pair in the case of a map. Simply specializing the result for map makes it work (using ref as noted by ildjarn).
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/foreach.hpp>
#include <string>
#include <iostream>
#include <vector>
#include <map>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace boost { namespace phoenix { namespace stl {
template <typename This, typename Key, typename Value, typename Compare, typename Allocator, typename Index>
struct at_impl::result<This(std::map<Key,Value,Compare,Allocator>&, Index)>
{
typedef Value & type;
};
template <typename This, typename Key, typename Value, typename Compare, typename Allocator, typename Index>
struct at_impl::result<This(std::map<Key,Value,Compare,Allocator> const&, Index)>
{
typedef Value const& type;
};
}}}
int main() {
std::map<unsigned int, unsigned int> myMap;
myMap[1] = 100; myMap[2] = 200; myMap[3] = 300;
std::string test = "1 2 3";
std::vector<unsigned int> results;
qi::rule<std::string::iterator, unsigned int()> r
= qi::uint_ [qi::_val = phx::at(phx::cref(myMap), qi::_1)];
qi::parse(test.begin(), test.end(), ( r % " " ), results);
BOOST_FOREACH(unsigned int &x, results) {
std::cout << x << "\n";
}
}

Parsing a structure in an associative manner with Boost Spirit and Fusion

I'm trying to parse a key-value string into a structure. Some key-values may be absent or may be in different order, so I wanted to use boost::fusion to adapt the structure and then parse into it with at_key<> directive.
#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/sequence.hpp>
using namespace std;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phx = boost::phoenix;
using boost::fusion::at_key;
typedef string::const_iterator iter_type;
struct Couple {
int a;
int b;
Couple() : a(0), b(0) {}
};
namespace keys {
struct first;
struct second;
}
BOOST_FUSION_ADAPT_ASSOC_STRUCT(
Couple,
(int, a, keys::first)
(int, b, keys::second)
)
struct G: qi::grammar< iter_type, Couple(), ascii::space_type >
{
G() : G::base_type( start_rule ) {
using qi::_val;
using qi::_1;
using qi::_2;
start_rule =
( "first" >> qi::int_
[ at_key<keys::first>(_val) = _1 ]
)
^
( "second" >> qi::int_
[ at_key<keys::second>(_val) = _1 ]
);
}
qi::rule< iter_type, Couple(), ascii::space_type > start_rule;
};
int main() {
Couple couple;
string example = "second 2 first 1";
iter_type begin( example.begin() );
iter_type end( example.end() );
// test at_key -- compiles with no error
at_key<keys::second>(couple) = 5;
bool ok = qi::phrase_parse( begin, end, G(), ascii::space, couple );
if ( ok )
cout << couple.a << " " << couple.b << endl;
else
cout << "Parse failed" << endl;
return 0;
}
The problem is that the code does not compile (Boost 1.50.0, g++ 4.5.0, MinGW), apparently fails at the at_key<> rules:
In file included from D:\projects\workspace\boost/boost/fusion/support/category_of.hpp:10:0,
from D:\projects\workspace\boost/boost/fusion/include/category_of.hpp:10,
from D:\projects\workspace\boost/boost/proto/fusion.hpp:20,
from D:\projects\workspace\boost/boost/proto/core.hpp:21,
from D:\projects\workspace\boost/boost/proto/proto.hpp:12,
from D:\projects\workspace\boost/boost/spirit/home/support/meta_compiler.hpp:19,
from D:\projects\workspace\boost/boost/spirit/home/qi/meta_compiler.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi.hpp:14,
from D:\projects\workspace\boost/boost/spirit/include/qi.hpp:16,
from ..\src\spirit02_test.cpp:11:
D:\projects\workspace\boost/boost/fusion/support/detail/category_of.hpp: In instantiation of 'boost::fusion::detail::fusion_category_of<const boost::phoenix::actor<boost::spirit::attribute<0> > >':
D:\projects\workspace\boost/boost/fusion/support/category_of.hpp:44:58: instantiated from 'boost::fusion::extension::category_of_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> > >'
D:\projects\workspace\boost/boost/fusion/support/category_of.hpp:66:9: instantiated from 'boost::fusion::traits::category_of<const boost::phoenix::actor<boost::spirit::attribute<0> > >'
D:\projects\workspace\boost/boost/fusion/support/category_of.hpp:73:9: instantiated from 'boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >'
D:\projects\workspace\boost/boost/mpl/if.hpp:67:11: instantiated from 'boost::mpl::if_<boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >, boost::fusion::result_of::key_of<mpl_::arg<1> >, boost::fusion::result_of::value_of<mpl_::arg<1> > >'
D:\projects\workspace\boost/boost/fusion/algorithm/query/find.hpp:45:9: instantiated from 'boost::fusion::result_of::find<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:38:17: instantiated from 'boost::fusion::extension::at_key_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:71:9: instantiated from 'boost::fusion::result_of::at_key<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
..\src\spirit02_test.cpp:54:35: instantiated from here
D:\projects\workspace\boost/boost/fusion/support/detail/category_of.hpp:15:38: error: no type named 'category' in 'const struct boost::phoenix::actor<boost::spirit::attribute<0> >'
In file included from D:\projects\workspace\boost/boost/proto/args.hpp:21:0,
from D:\projects\workspace\boost/boost/proto/core.hpp:14,
from D:\projects\workspace\boost/boost/proto/proto.hpp:12,
from D:\projects\workspace\boost/boost/spirit/home/support/meta_compiler.hpp:19,
from D:\projects\workspace\boost/boost/spirit/home/qi/meta_compiler.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi.hpp:14,
from D:\projects\workspace\boost/boost/spirit/include/qi.hpp:16,
from ..\src\spirit02_test.cpp:11:
D:\projects\workspace\boost/boost/mpl/if.hpp: In instantiation of 'boost::mpl::if_<boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >, boost::fusion::result_of::key_of<mpl_::arg<1> >, boost::fusion::result_of::value_of<mpl_::arg<1> > >':
D:\projects\workspace\boost/boost/fusion/algorithm/query/find.hpp:45:9: instantiated from 'boost::fusion::result_of::find<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:38:17: instantiated from 'boost::fusion::extension::at_key_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:71:9: instantiated from 'boost::fusion::result_of::at_key<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
..\src\spirit02_test.cpp:54:35: instantiated from here
D:\projects\workspace\boost/boost/mpl/if.hpp:67:11: error: 'value' is not a member of 'boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >'
D:\projects\workspace\boost/boost/mpl/if.hpp:70:41: error: 'value' is not a member of 'boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >'
In file included from D:\projects\workspace\boost/boost/fusion/sequence/intrinsic.hpp:20:0,
from D:\projects\workspace\boost/boost/fusion/include/intrinsic.hpp:10,
from D:\projects\workspace\boost/boost/proto/fusion.hpp:22,
from D:\projects\workspace\boost/boost/proto/core.hpp:21,
from D:\projects\workspace\boost/boost/proto/proto.hpp:12,
from D:\projects\workspace\boost/boost/spirit/home/support/meta_compiler.hpp:19,
from D:\projects\workspace\boost/boost/spirit/home/qi/meta_compiler.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi.hpp:14,
from D:\projects\workspace\boost/boost/spirit/include/qi.hpp:16,
from ..\src\spirit02_test.cpp:11:
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp: In instantiation of 'boost::fusion::extension::at_key_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>':
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:71:9: instantiated from 'boost::fusion::result_of::at_key<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
..\src\spirit02_test.cpp:54:35: instantiated from here
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:38:17: error: no type named 'type' in 'struct boost::fusion::result_of::find<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
..\src\spirit02_test.cpp: In constructor 'G::G()':
..\src\spirit02_test.cpp:54:35: error: no matching function for call to 'at_key(const boost::spirit::_val_type&)'
In file included from D:\projects\workspace\boost/boost/fusion/sequence/intrinsic.hpp:20:0,
from D:\projects\workspace\boost/boost/fusion/include/intrinsic.hpp:10,
from D:\projects\workspace\boost/boost/proto/fusion.hpp:22,
from D:\projects\workspace\boost/boost/proto/core.hpp:21,
from D:\projects\workspace\boost/boost/proto/proto.hpp:12,
from D:\projects\workspace\boost/boost/spirit/home/support/meta_compiler.hpp:19,
from D:\projects\workspace\boost/boost/spirit/home/qi/meta_compiler.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi.hpp:14,
from D:\projects\workspace\boost/boost/spirit/include/qi.hpp:16,
from ..\src\spirit02_test.cpp:11:
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp: At global scope:
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp: In instantiation of 'boost::fusion::extension::at_key_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::second>':
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:71:9: instantiated from 'boost::fusion::result_of::at_key<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::second>'
..\src\spirit02_test.cpp:58:36: instantiated from here
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:38:17: error: no type named 'type' in 'struct boost::fusion::result_of::find<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::second>'
..\src\spirit02_test.cpp: In constructor 'G::G()':
..\src\spirit02_test.cpp:58:36: error: no matching function for call to 'at_key(const boost::spirit::_val_type&)'
If I use a simpler rule (without associativity), everything compiles and works fine, but this solution is somewhat fragile:
// A non-associative solution
//start_rule %= ( ("first" >> qi::int_) ^ ("second" >> qi::int_) );
Why cannot I use at_key in the semantic action? Is there a better way to do an "associative" parse into a non-associative structure?
You need a lazy version of at_key. The patch for this sadly never made it into Spirit (yet):
/*=============================================================================
Copyright (c) 2005-2008 Hartmut Kaiser
Copyright (c) 2005-2007 Joel de Guzman
Copyright (c) 2011 Michael Caisse
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 PHOENIX_SEQUENCE_AT_KEY_HPP
#define PHOENIX_SEQUENCE_AT_KEY_HPP
#include <boost/fusion/include/at_key.hpp>
#include <boost/spirit/home/phoenix/core/actor.hpp>
#include <boost/spirit/home/phoenix/core/compose.hpp>
#include <boost/type_traits/remove_reference.hpp>
namespace boost { namespace phoenix
{
template <typename Key>
struct at_key_eval
{
template <typename Env, typename Tuple>
struct result
{
typedef typename Tuple::template result<Env>::type tuple;
typedef typename
fusion::result_of::at_key<
typename remove_reference<tuple>::type, Key
>::type
type;
};
template <typename RT, typename Env, typename Tuple>
static RT
eval(Env const& env, Tuple const& t)
{
return fusion::at_key<Key>(t.eval(env));
}
};
template <typename Key, typename Tuple>
inline actor<typename as_composite<at_key_eval<Key>, Tuple>::type>
at_key(Tuple const& tup)
{
return compose<at_key_eval<Key> >(tup);
}
}}
#endif
If you add it, you can use boost::phoenix::at_key:
using boost::phoenix::at_key;
Things will compile and work as expected. The linked patch also modifies boost/spirit/home/phoenix/fusion.hpp to include this new header, of course.

Using the + operator in boost::spirit: char cast error?

In boost::spirit, I am trying to use the +(...) syntax to match one or more strings, like here:
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
bool parse(Iterator first, Iterator last)
{
using qi::char_;
qi::rule< Iterator, std::string(), ascii::space_type > text;
qi::rule< Iterator, std::string() > myword;
text = '"' >> +( myword ) >> '"'; // ERROR!
myword = +char_;
bool r = qi::phrase_parse(first, last, text, ascii::space);
if (first != last)
return false;
return r;
}
}
But I'm getting the following error:
foo.cpp:20: instantiated from 'bool client::parse
boost/spirit/home/qi/detail/assign_to.hpp:109: error: \
invalid static_cast from type \
'const std::basic_string<char, std::char_traits<char>, std::allocator<char> >' \
to type 'char'
Does anyone know what I'm doing wrong?
Your code compiles just fine with Boost V1.47 (Spirit V2.5). In this version of Spirit the attribute handling has been completely rewritten which fixes this issue (and a lot of other issues).