I'm using boost spirit to parse some text. For this I have two grammars. The first one parses a string into a struct, the second one, takes a grammar as template argument and uses it to parse a sequence of data. The second parser should be flexible enough to also handle other grammar return types. Since the original parser is too large to act as a minimal example, I have reduced the code as much as I can, leaving me with something that would not parse anything, but still results in the same compilation errors: (Code on Coliru)
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <vector>
namespace ascii = boost::spirit::ascii;
namespace qi = boost::spirit::qi;
struct Struct1
{
float f;
};
BOOST_FUSION_ADAPT_STRUCT(
Struct1,
(float, f))
struct Struct2
{
float f;
int i;
};
BOOST_FUSION_ADAPT_STRUCT(
Struct2,
(float, f)
(int, i))
template<typename Iterator,
typename Result>
class ElementParser : public qi::grammar<Iterator, Result(), ascii::space_type>
{
public:
using ValueType = Result;
ElementParser() : ElementParser::base_type(element) {}
private:
qi::rule<Iterator, Result(), ascii::space_type> element;
};
template<typename Iterator,
typename ElementParser,
typename Element = typename ElementParser::ValueType>
class SP : public qi::grammar<Iterator, std::vector<Element>(), ascii::space_type>
{
public:
SP()
: SP::base_type(sequence)
{
sequence %= simpleVector % ',';
// The simpleVector hack is really needed because of some other parsing
// stuff, that is going on, but has been left out here.
simpleVector %= qi::repeat(1)[simple];
}
private:
using Rule = qi::rule<Iterator, std::vector<Element>(), ascii::space_type>;
Rule sequence;
Rule simpleVector;
ElementParser simple;
};
void sequenceTest()
{
using Iterator = std::string::const_iterator;
SP<Iterator, qi::uint_parser<>, std::size_t> uintParser; // OK
SP<Iterator, ElementParser<Iterator, float>> floatParser; // OK
SP<Iterator, ElementParser<Iterator, std::vector<float>>> vectorParser; // OK
// error: invalid static_cast from type 'const std::vector<Struct1, std::allocator<Struct1> >' to type 'element_type' {aka 'float'}
SP<Iterator, ElementParser<Iterator, Struct1>> struct1Parser;
// error: no matching function for call to 'Struct2::Struct2(const std::vector<Struct2, std::allocator<Struct2> >&)'
SP<Iterator, ElementParser<Iterator, Struct2>> struct2Parser;
}
As long, as I am using simple types or vectors as return types of the ElementParser
, everything is working fine, but as soon as I'm parsing into a struct (which in itself is working fine), the sequence parser SP
seems to try some stange assignments. Why do the struct versions result in compilation errors?