1
votes

I have written a working token parser based on the code shown at spirit lex example 4

One of my rules looks like this

    set_name 
        =   (   tok.set_ >> tok.name_ >> tok.identifier )
            [
                std::cout << val("set name statement to: ") << _3 << "\n"
            ]
        ;

This works well. When presented with

SET NAME xyz

it outputs as I expect

set name statement to: xyz

Now I want to do something useful, store the name found into a class. Working from parser semantic examples I write this code

  class writer
    {
    public:
        void print(string const& s) const
        {
            std::cout << s << std::endl;
        }
    };

  writer w;

  ...

    set_name 
        =   (   tok.set_ >> tok.name_ >> tok.identifier )
            [
                boost::bind( &writer::print, &w, ::_3 )
            ]
        ;

This does not compile

1>C:\Program Files\boost\boost_1_44\boost/bind/bind.hpp(318) : error C2664: 'R boost::_mfi::cmf1::operator ()(const U &,A1) const' : cannot convert parameter 2 from 'bool' to 'const std::basic_string '
1>        with
1>        [
1>            R=void,
1>            T=eCrew::rule::writer,
1>            A1=const std::string &,
1>            U=eCrew::rule::writer *
1>        ]
1>        and
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits,
1>            _Ax=std::allocator
1>        ]
1>        Reason: cannot convert from 'bool' to 'const std::string'
1>        No constructor could take the source type, or constructor overload resolution was ambiguous

Why is the compiler complaining about a trying to convert from bool to string? There is no bool that I can see.

1
In ... is w being redeclared as a bool? What happens if you use a more unique variable name for the writer?jon-hanson
@jon changed "w" to "the_writer". Same result.ravenspoint

1 Answers

3
votes

The placeholder in

std::cout << val("set name statement to: ") << _3 << "\n"

refers to boost::spirit::_3, which is a boost.phoenix v2 placeholder. The placeholder in

boost::bind(&writer::print, &w, ::_3)

is a boost.bind placeholder (naturally).

These placeholders do not share the same behavior, or even refer to the same data. Phoenix placeholders of the form _N refer to the Nth subattribute of your parser, while bind placeholders have a different meaning:

  • _1 refers to your parser's attribute as a whole
  • _2 refers to the parser's context
  • _3 refers to a bool& 'hit' parameter

The easiest solution in your case is to use boost::phoenix::bind instead of boost::bind, so that you can continue using _3 to refer to the third subattribute of your parser instead of having to pick it out manually inside of writer::print.

Alternatively, only attach the semantic action to tok.identifier so that boost.bind's ::_1 works as you expect:

set_name
  = tok.set_
    >> tok.name_
    >> tok.identifier[boost::bind(&writer::print, &w, ::_1)]
;