Search code examples
c++booststlboost-spiritboost-fusion

Which container types are supported by a boost::spirit parser and boost::fusion?


I'd like to ask this question on a very generic level: How far does the support of container types by boost::spirit / boost::fusion reach? Can anybody give me some generic guidance on what is possible and what is not possible?

With "support" I mean the following: With the following parser definition I can parse directly into a std::pair<double,double> :

template <typename Iterator>
struct pair_parser
    :     qi::grammar<Iterator, std::pair<double,double>()>
{
    pair_parser() : pair_parser::base_type(start)
    {
         start = pair;
         pair  = qi::double_ >> ":" >> qi::double >> ";"
    }
    qi::rule<Iterator, std::pair<double,double>()> pair;
};

Do I understand it correctly that the whole "magick" is done by boost::fusion? With that in mind let me define that: pair of doubles is supported.

I have found working examples for the following:

 std::vector<std::string>
 std::map<std::string, std::string>   // the trick is not to forget the pair within
 std::vector<std::vector<int> >
 struct A{int, double, std::string}   // with boost::fusion adaptor

and I have worked out the following:

std::map<std::string,  boost::variant<int, double, std::string> >

So, I further say that:

  • vector of strings
  • simple name-value maps
  • vector of vector of POD-types
  • boost::variant
  • structs

are supported by boost::spirit / boost::fusion.

But, does it also work with the other STL containers? Are generally all of them supported or are there some that don't work? What about the boost::containers? How about nested containers? How deeply can they be nested? How about nested structs? What do I need to understand to identify whether a container is possible to use with boost::spirit / boost::fusion?

Background: I'm trying to parse into slightly more complex types like this struct table with a boost::multi_array and a "vector of map of double and struct":

struct skewFactor{
    double horizontalSkew;
    double verticalSkew;
    double factor;
};
struct table {
    std::vector<std::vector<double> > index;
    boost::multi_array<double,4> baseArray; // yes, this array is 4-dimensional
    std::vector<std::map<double, skewFactor> > effect;
};

Currently I'm just working it out with trial-and-error.


Solution

  • Apparently I am about the only person interested in using boost::multi_array together with boost::spirit. There was some interest int the same question back in 2010 by Stephen Torri.

    I have made progress with the struct table; above. The nested vectors, map and structs are well supported by boost::fusion. However, boost::multi_array is still waiting for a solution. One of the biggest stumble blocks is the notorious lack of good examples. (I'll possibly add some examples later)

    The solutions to nested vectors and maps were sparked by the study of the "Parsers in Depth" section of the boost::spirit documentation. I'd like to stress again my previous statement in a comment above: Disregard the advice in the boost::spirit documentation: "This section is not for the faint of heart." It contains valuable information that is absolutely required as soon as you leave the very trivial examples. Another important point is to understand the relations between the boost libraries itself:

    • fusion: a library for serializing any datatype. It is used for the "automatic" data propagation within the spirit grammar.
    • phoenix: a library for functional programming.
    • spirit: the parser library itself. it is built with and on top of phoenix. Functional programming is the key to understand the parsers and the semantic actions.

    For the boost::multi_array I decided to follow another path: semantic actions. Although they are frowned upon in the boost::spirit community, I've decided to use them because I also have to perform some transformations in the arrays. With boost::phoenix I'm (nearly) able to populate the arrays without relying on boost::fusion.