Search code examples
boost-spirit-qiboost-phoenix

Why can't I seem to use qi locals as the semantic predicate to eps?


When using qi::locals, a local parameter doesn't seem like it can be used as the semantic predicate to eps. Here is a stripped down fictional example:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
using namespace qi::labels;
using qi::eps;

template <typename Iterator, typename Any>
struct parser : qi::grammar<Iterator, Any(), qi::locals<bool> > {
    parser() : parser::base_type(p) {
        p = eps[_a=false] >> eps(_a);
    }
    qi::rule<Iterator, Any(), qi::locals<bool> > p;
};

int main(int argc, const char *argv[]) {
    int val;
    std::string data;
    auto i = data.cbegin();
    auto end = data.cend();
    parser<decltype(i), decltype(val) > p;
    bool rv = phrase_parse(i, end, p, ascii::blank, val);
    return rv ? 0 : 1;
}

In this example, if I remove the (_a) after the second eps, everything compiles cleanly. With the (_a), I get a morass of failed template instantiation. The context doesn't matter, as I have solved this problem in my real code-base another way, but I would like to know why this does not work.


Solution

  • On my compilers/boost versions it works See also Live On Coliru

    On a whim I'm suspecting bugs that have crept into the "old" Phoenix V2 implementation. Phoenix V2 was still a part of the Spirit Library technically. It has been superseded by Phoenix V3 which lives as the separate library in boost/phoenx/....

    Boost Phoenix V2 is showing cracks of age - mainly on modern compilers where the BOOST_RESULT_OF() utilities use decltype.

    Long story short

    1. try using

       #define BOOST_SPIRIT_USE_PHOENIX_V3
      

      to use it iff your compiler/boost combination doesn't select it.¹

    2. inversely, if your compiler is oldish, try

      #define BOOST_RESULT_OF_USE_TR1
      

    ¹ Recent Spirit versions dropped Phoenix V2 : Farewell Phoenix-v2