1

Given the following actions

struct Data {
    double d;
    void operator()( double dd,
                     boost::spirit::qi::unused_type,
                     boost::spirit::qi::unused_type )
    { d = dd; }
};

struct Printer {
    void operator()( double dd,
                     boost::spirit::qi::unused_type,
                     boost::spirit::qi::unused_type ) const
    { std::cout << dd; }
};

the code

void foo( const std::string &s ) {
    Printer p;
    boost::spirit::qi::parse( s.begin(), s.end(),
                              boost::spirit::qi::double_[ p ] );
}

does compile while

double foo( const std::string &s ) {
    Data d;
    boost::spirit::qi::parse( s.begin(), s.end(),
                              boost::spirit::qi::double_[ d ] );
    return d.d;
}

does not.

Looking at the examples in http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/spirit/qi/tutorials/semantic_actions.html, one sees that the function objects use a operator() declared const. The error message C3848 of MSVC suggests something similar.

Is constness required here? The documentation in http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/spirit/qi/reference/action.html only says the signature void( Attrib&, Context, bool& ) is required.

Remark: I must admit I don't really understand the sentence

The function or function object is expected to return the value to generate output from by assigning it to the first parameter, attr.

in this context.

mkluwe
  • 3,823
  • 2
  • 28
  • 45

1 Answers1

3

Q.2: Remark: I must admit I don't really understand the sentence

A. You could look at boost spirit semantic action parameters for indepth explanation of it. Here is the short version:

void action_f(std::string& attribute, 
        qi::unused_type const& context, 
        bool& flag)
{
    boost::fusion::at_c<0>(context.attributes) = "hello world"; // return the attribute value
    flag = true; // signal parse success
}

Q.1: Is constness required here? The documentation in http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/spirit/qi/reference/action.html only says the signature void( Attrib&, Context, bool& ) is required.

A. The const-ness may not be explicitely required by the library, however the requirement is implicitely introduced by the C++ language due the way you are using the parser expression1:

The expression template

boost::spirit::qi::double_[ d ]

yields a temporary, which when passed to the qi::parse API can only get bound to a const reference2,3. This is where the 'const' on the whole parser expresion is introduced, and it extends equally to members of the subexpression(s), such as those that store the semantic action, d.

Therefore the instance of d at the time of deferred invocation will be logically const and therefore the operator() will not be selected, whereas operator() const will.


1. Upon more thought, it doesn't really depend on how you use it. The logic of my explanation is sound, but because spirit even supports inline parser expressions, call()-ing parsers is necessarily a const member operation on that parser, and as such all other operations will be in const context anyway. And indeed, in boost::spirit::traits::action_dispatch::operator() you'll see the calleables being passed as F const&, e.g. reflecting this.

2. Spirit V2 does not support move semantics for rules - nor, indeed, does it require them

3. The lifetime of the temporary will be extends to the end of the containing full expression, as per standardese

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633