I'm facing with a compilation error in a program I'm writing using boost1.54 and clang++-3.9. Consider the following (simplified) example code:
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
using namespace boost::spirit;
struct some_stuff {
struct return_type {
unsigned int field_1;
};
struct id : qi::grammar<std::string::iterator>{
id() : id::base_type(rule_){ rule_ = qi::lit("?AL"); }
private:
qi::rule<std::string::iterator> rule_;
};
struct payload : qi::grammar<std::string::iterator, return_type()> {
payload() : payload::base_type{rule_} { rule_ = qi::uint_; }
private:
qi::rule<std::string::iterator, return_type()> rule_;
};
};
BOOST_FUSION_ADAPT_STRUCT(some_stuff::return_type, (unsigned int, field_1))
struct my_grammar : qi::grammar<std::string::iterator, some_stuff::return_type()>{
my_grammar() : my_grammar::base_type(rule_){ rule_ = "+++AT" >> i_ >> ':' >> qi::omit[qi::uint_] >> ':' >> p_; }
private:
some_stuff::id i_;
some_stuff::payload p_;
qi::rule<std::string::iterator, some_stuff::return_type()> rule_;
};
int main() {
std::string s("+++AT?AL:1:3,5");
my_grammar g_;
some_stuff::return_type v_;
auto it = s.begin();
if (qi::phrase_parse(it, s.end(), g_, ascii::space, v_)) {
std::cout << "Field 1: " << v_.field_1 << std::endl;
}
return 0;
}
When I try to compile it, I get the error reported in the title:
error: cannot convert 'const some_stuff::return_type' to 'unsigned int' without a conversion operator
However, if I add the cast operator to unsigned int in the struct some_stuff::return_type
everything works fine.
Can someone help me to understand why the cast operator is mandatory in this case or, in case it is not, how to solve this issue?
You've been bit by the infamous "single-element sequence" bug/limitation: Spirit Qi attribute propagation issue with single-member struct
Adding a dummy
field to return_type
make it work (also added debugging):
#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
using namespace boost::spirit;
struct some_stuff {
struct return_type {
unsigned int field_1;
bool dummy;
};
struct id : qi::grammar<std::string::iterator> {
id() : id::base_type(rule_) {
rule_ = qi::lit("?AL");
BOOST_SPIRIT_DEBUG_NODES((rule_))
}
private:
qi::rule<std::string::iterator> rule_;
};
struct payload : qi::grammar<std::string::iterator, return_type()> {
payload() : payload::base_type{ rule_ } {
rule_ = qi::uint_ >> qi::attr(false);
BOOST_SPIRIT_DEBUG_NODES((rule_))
}
private:
qi::rule<std::string::iterator, return_type()> rule_;
};
};
BOOST_FUSION_ADAPT_STRUCT(some_stuff::return_type, field_1, dummy)
struct my_grammar : qi::grammar<std::string::iterator, some_stuff::return_type()> {
my_grammar() : my_grammar::base_type(rule_) {
rule_ = "+++AT" >> i_ >> ':' >> qi::omit[qi::uint_] >> ':' >> p_;
BOOST_SPIRIT_DEBUG_NODES((rule_))
}
private:
some_stuff::id i_;
some_stuff::payload p_;
qi::rule<std::string::iterator, some_stuff::return_type()> rule_;
};
int main() {
std::string s("+++AT?AL:1:3,5");
my_grammar g_;
some_stuff::return_type v_;
auto it = s.begin();
if (qi::phrase_parse(it, s.end(), g_, ascii::space, v_)) {
std::cout << "Field 1: " << v_.field_1 << std::endl;
}
}
Prints
<rule_>
<try>+++AT?AL:1:3,5</try>
<rule_>
<try>?AL:1:3,5</try>
<success>:1:3,5</success>
<attributes>[]</attributes>
</rule_>
<rule_>
<try>3,5</try>
<success>,5</success>
<attributes>[[3, 0]]</attributes>
</rule_>
<success>,5</success>
<attributes>[[3, 0]]</attributes>
</rule_>
Field 1: 3
You're using phrase_parse
without a skipper. That's not working, and not what you want: Boost spirit skipper issues