3

Imagine we want to parse and generate simple C++ member function declarations with Boost.Spirit.

The Qi grammar might look like this:

function_ %= type_ > id_ > "()" > matches["const"];

That means, whether the function is const is stored in a bool.

How to write the corresponding generator with Karma?

function_ %= type_ << ' ' << id_ << "()" << XXX[" const"];

Here, we want a directive that consumes a boolean attribute, executes the embedded generator if the attribute is true and does nothing otherwise. We want something that makes the following tests succeed.

test_generator_attr("abc", XXX["abc"], true);
test_generator_attr("", XXX["abc"], false);

Is such a directive already available in Boost.Spirit?

purpleKarrot
  • 156
  • 8

1 Answers1

2

The first thing that enters my mind at the moment is

bool const_qualifier = true;

std::cout << karma::format(
      karma::omit[ karma::bool_(true) ] << " const" | "",
      const_qualifier);

It feels a bit... clumsy. I'll have a look later what I'm forgetting :)

UPDATE Here's a slightly more elegant take using karma::symbols<>:

#include <boost/spirit/include/karma.hpp>

namespace karma = boost::spirit::karma;

int main()
{
    karma::symbols<bool, const char*> const_;
    const_.add(true, "const")(false, "");

    for (bool const_qualifier : { true, false })
    {   
        std::cout << karma::format_delimited("void foo()" << const_, ' ', const_qualifier) << "\n";
    }   
}

Prints:

void foo() const 
void foo()  
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Yeah. I think the `symbols<>` approach is the cleanest I've seen. Updated answer. – sehe Aug 26 '14 at 10:25
  • The `symbols` approach is great (although it would not work if the "subject generator" is more complex than a simple string). Your initial approach reminds me of [this example](http://www.boost.org/libs/spirit/example/karma/complex_number_adapt.cpp) where they use something like `&true_ << " const" | omit[bool_]` (maybe followed by `<< ""`). – llonesmiz Aug 26 '14 at 11:39
  • @cv_and_he Agreed. Perhaps a sort of Nabialek-derivative is in order for more complicated branches (using `karma::lazy` and `karma::symbols >`) – sehe Aug 26 '14 at 11:41
  • `(!bool_(true) | " const")` is probably most concise. Still, a generator directive would make the code easier to read. – purpleKarrot Aug 27 '14 at 13:07
  • @purpleKarrot I think that fails to consume the attribute, but I'll check later. – sehe Aug 27 '14 at 13:24
  • 2
    @sehe @purpleKarrot While trying to implement a generator directive, I've convinced myself that if the "subject generator" is complex, you are better served by `boost::optional` and Karma's optional generator operator, so I'd like to amend my previous comment to just "The `symbols` approach is great.". You can find [here](http://coliru.stacked-crooked.com/a/485374e415d99c56) an awfully named (and practically untested) directive that I think does what you want for embedded generators that have an unused attribute. – llonesmiz Aug 28 '14 at 08:49