2

I'm trying to create a simple parser that takes one of two possible characters using boost::spirit::x3. The problem is that x3::char_('#') | x3::char_('.') seems to have an attribute of type boost::variant<char, ?>. This means I have to use boost::get<char> on the _attr, whereas it should be directly convertible to a char.

http://ciere.com/cppnow15/x3_docs/spirit/quick_reference/compound_attribute_rules.html, it says A | A -> A

If the commented out version of mapChars is used then it's convertible to a char, but not the |.

I am on boost version 1.63.0 and on Linux. The code fails to compile on both g++ and clang++ with -std=c++14.

What am I doing wrong?

#include <iostream>
#include <string>

#include <boost/spirit/home/x3.hpp>

int main() {
    std::string s("#");
    namespace x3 = boost::spirit::x3;
    auto f = [](auto & ctx) {
        auto & attr = x3::_attr(ctx);
        //char c = attr; // doesn't work
        char c = boost::get<char>(attr); // does work
    };
    auto mapChar = x3::char_('#') | x3::char_('.'); // _attr not convertible to char, is a variant
    //auto mapChar = x3::char_('#'); // _attr convertible to char, isn't a variant
    auto p = mapChar[f];
    auto b = s.begin();
    bool success = x3::parse(b, s.end(), p);
    std::cout << "Success: " << success << ' ' << (b == s.end()) << '\n';
}
aeubanks
  • 1,261
  • 1
  • 12
  • 12

2 Answers2

1

You are correct, it should be compatible, and indeed it already is:

auto const& attr = x3::_attr(ctx);
char c;
x3::traits::move_to(attr, c);

Spirit's attribute compatibility rules (plus the customization point) is the vehicle to carry such semantics.

I agree with you that it could be a nice usability improvement iff the attribute type could be simplified to be char directly, but I reckon this has further-reaching consequences further down the road.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • I tried that and that basically gives the same error (`assigning to char from incompatible type ...>...`). It seems that in this case `x3::traits::move_to` is just doing `dest = std::move(src);` which doesn't change anything. – aeubanks Feb 10 '17 at 15:41
  • 2
    @aeubanks Mmm. You're quite right. I must have done something wrong. Meanwhile, you can use rule coercion ([demo](http://coliru.stacked-crooked.com/a/a7f8df9f67ac3a7b)) which becomes a lot more convenient [with a helper function](http://stackoverflow.com/questions/33816662/understanding-the-list-operator-in-boost-spirit/33817135#33817135): http://coliru.stacked-crooked.com/a/1f5788a7eeaf872b – sehe Feb 10 '17 at 16:14
  • If you feel this should be discussed for improvement you can reach the developers at [spirit-general] mailing list – sehe Feb 10 '17 at 16:15
0

If your semantic action takes the attribute by value, it should work:

char result = 0;

auto f = [&result](char c){ result = c; };

auto mapChar = x3::char_('#') | x3::char_('.');
auto p = mapChar[f];
auto b = s.begin();
bool success = x3::parse(b, s.end(), p);
Boris Glick
  • 202
  • 1
  • 4