Detecting the parameter types in a Spirit semantic action
boost-spirit, c++, compiler-errors
Solution
For clarity - the error here is that `base_ >> int_ >> int_` was used as the expression for a rule that creates a `myderived`, and since `base_` is fixed to type `mybase`, we'd have to create a `myderrived` from a `mybase` and two `int`s, but there's nothing to tell Spirit how to do that.
You can get boost to print out the type of the value that boost creates from parsing `base_ >> int_ >> int_` by defining a functor that will take any parameters, and tell you what they are (the following code is adapted from some code sehe put on SO chat):
struct what_is_the_attr
{
template <typename> struct result { typedef bool type; };
template <typename T>
static void print_the_type()
{
std::cout << " ";
std::cout << typeid(T).name();
if(std::is_const<typename std::remove_reference<T>::type>::value)
std::cout << " const";
if(std::is_rvalue_reference<T>::value)
std::cout << " &&";
else if(std::is_lvalue_reference<T>::value)
std::cout << " &";
}
template <typename Th, typename Th2, typename... Tt>
static void print_the_type()
{
print_the_type<Th>();
std::cout << ",\n";
print_the_type<Th2, Tt...>();
}
template <typename... Ts>
void operator()(Ts&&...) const
{
std::cout << "what_is_the_attr(\n";
print_the_type<Ts...>();
std::cout << ")" << std::endl;
}
};
Then to use it, use the above actor in a semantic action on initializer for your faulty rule:
std::string input = "1 2 3 4";
auto f(std::begin(input)), l(std::end(input));
rule<decltype(f), mybase() , space_type> base_ = int_ >> int_;
rule<decltype(f), myderived(), space_type> derived_ = (base_ >> int_ >> int_)[what_is_the_attr()];
myderived data;
bool ok = phrase_parse(f,l,derived_,space,data);
Note, you cannot use automatic attribute propagation with `%=` (unless you remove the exposed attribute type from the rule's declared type).
Running this should then yield an encoded type, which can be decoded with `c++filt -t`: Live On Coliru
$ g++ 9404189.cpp -std=c++0x
$ ./a.out |c++filt -t
what_is_the_attr(
boost::fusion::vector3<mybase, int, int> &,
boost::spirit::context<boost::fusion::cons<boost::spirit::unused_type&, boost::fusion::nil>, boost::fusion::vector0<void> > &,
bool &)
The first line, `boost::fusion::vector3<mybase, int, int>`, least tells you that boost is trying to create your return type from 3 objects of types `mybase`, `int` and `int`.
Problem
General case: I can't figure out why my Spirit grammar/semantics actions aren't compiling. Sometimes, the compiler will complain about assignment or type incompatibilities and I have no clue what's wrong. The problem occurs in two main areas: - predicting the type of synthesized attributes for a rule/expression - consequently, predicting what types of attributes can be legally defined as the exposed attribute for the rule (relying in builting conversions, fusion adaptors or Spirit customization points) - matching the argument types for my semantic action so that - the compiler will be able to compile the function invocation - the invocation will not invoke unnecessary implicit conversions in the process The compiler error is not exactly tractable, and either the documentation is wrong, or I misunderstood it. Is there a way to find out exactly what Spirit passes into my semantic action, anyway? Example code: ``` struct mybase { int a,b; }; struct myderived : mybase { int c,d; }; BOOST_FUSION_ADAPT_STRUCT(mybase, (int,a)(int,b)); BOOST_FUSION_ADAPT_STRUCT(myderived, (int,a)(int,b)(int,c)(int,d)); auto base_expr = int_ >> int_; // avoids assigning to struct attribute rule<decltype(f), mybase() , space_type> base_ = int_ >> int_; rule<decltype(f), myderived(), space_type> derived_ = base_ >> int_ >> int_; myderived data; bool ok = phrase_parse(f,l,derived_,space,data); ``` This code won't compile, with a huge amount of impenetrable errors. (loosely adapted from a posting on the spirit-general list)