Take the 2-minute tour ×

I have the following parsing rule:

filter = (input >> (qi::repeat(0,2)[char_(';') >> input]))

input is a rule that returns a std::vector<int>, vector that I will just call vec for short.

The question is: What compound attribute would the filter rule return?

I tried:

fusion::vector <vec,std::vector <fusion::vector <char,vec> > >

But it fails and I don't know why.

share|improve this question
Oh. Lol I somehow read vec of short instead of for short. Oh well, s/short/int/ in my answer wlll do –  sehe Jul 26 '13 at 8:37

1 Answer 1

up vote 5 down vote accepted

The attribute types resulting of the parser expressions are quite well-documented. But that can be disorienting and timeconsuming.

Here's a trick: send in a sentinel to detect the attribute type:

struct Sniffer
    typedef void result_type;

    template <typename T>
    void operator()(T const&) const { std::cout << typeid(T).name() << "\n"; }

then using the folliing parser expression

 (input >> (qi::repeat(0,2)[qi::char_(';') >> input])) [ Sniffer() ]

will dump:


which c++filt -1 will tell you represents:

    std::vector<short, std::allocator<short> >, 
    std::vector<boost::fusion::vector2<char, std::vector<short, std::allocator<short> > >, 
                std::allocator<boost::fusion::vector2<char, std::vector<short, std::allocator<short> > > 
            > > 

See it live on Coliru: http://coliru.stacked-crooked.com/view?id=3e767990571f8d0917aae745bccfa520-5c1d29aa57205c65cfb2587775d52d22

boost::fusion::vector2<std::vector<short, std::allocator<short> >, std::vector<std::vector<short, std::allocator<short> >, std::allocator<std::vector<short, std::allocator<short> > > > >

It might be so surprisingly complicated, in part, because char_(";") could have been ';' (or more explicitely lit(';')). Constrast with this (Coliru):

    std::vector<short, ... >, 
    std::vector<std::vector<short, std::allocator<short> >, ... > >

This should answer your question.

Sidenotes: parsing things

Don't underestimate automatic attribute propagation in Spirit. Frequently, you don't have to bother with the exact exposed types of attributes. Instead, rely on the (many) attribute transformations that Spirit uses to assign them to your supplied attribute references.

I trust you know the list-operator (%) in spirit? I'll show you how you can use it without further ado:

vector<vector<short>> data;

qi::parse(f, l, qi::short_ % ',' % ';', data);

Now, if you need to enforce the fact that it may be 1-3 elements, you might employ an eps with a Phoenix action to assert the maximum size:

const string x = "1,2,3;2,3,4;3,4,5";
auto f(begin(x)), l(end(x));

if (qi::parse(f, l, 
        (qi::eps(phx::size(qi::_val) < 2) > (qi::short_ % ',')) % ';'
        , data))
    cout << karma::format(karma::short_ % ',' % ';', data) << "\n";
cout << "remaining unparsed: '" << std::string(f,l) << "'\n";


remaining unparsed: ';3,4,5'
share|improve this answer
First of all, thanks for the detailed and informative answer! The strange thing is that the attribute that your code suggests is the same as the one I tried! The only difference is that you are explicitly specifying a fusion::vector2 and I was just naming it a fusion::vector that takes 2 template arguments. To my understanding, both should be equivalent. To sum it up, this works: fusion::vector <vec,std::vector <fusion::vector2 <char,vec> > > while this doesn't: fusion::vector <vec,std::vector <fusion::vector <char,vec> > > I don't know if it's a bug or what. –  jay1189947 Jul 26 '13 at 13:25
Notice how I never had to specify a fusion::vector2 in the first one, so I don't really know why I have to do it for the second (Bug maybe?). Your answer and attribute detector guided me in the right direction, so I'm voting your answer as correct, but I still don't know why I'm forced to use fusion::vector2 in this case. –  jay1189947 Jul 26 '13 at 13:42
@jay1189947 Hmm. I think the most important take-away is this: Notice how I never even specify any fusion::* type at all. In my opinion, fusion sequences are an implementation detail, that you should only deal with when writing customization points, or perhaps when adapting structs (BOOST_FUSION_ADAPT_STRUCT). –  sehe Jul 26 '13 at 14:55
Also, note that container attributes have more 'magical' properties (like *int_ >> ';' >> *int_ can be used with a rule that exposes only a single std::vector<int>. But all this is getting a bit far afield. I suggest that experimenting a bit (and perhaps looking at the mechanics while doing so) is the best way to get intimate with the levels of convenience (and sometimes, surprise) that Boost Spirit has to offer. –  sehe Jul 26 '13 at 14:56
The thing is that I'm working with more complex structures, so I can't use the default synthesized attributes and need to use the rule context to build the attributes myself through semantic actions. I have read the documentation thoroughly multiple times, so I know how compound attributes are synthesized, which is precisely why I'm so confused that my first example doesn't work (and that I still claim is a bug). Thanks again for your time and replies! –  jay1189947 Jul 26 '13 at 15:59

Your Answer


