Domanda

I've tried to reduce this problem as far as I can.

If I uncomment void initialize(), then this code compiles. If I leave it commented out, then it doesn't build.

The only way I've found to fix this problem is to build in C++03 mode with boost::shared_ptr instead of std::shared_ptr.

I've attempted with the stock clang compiler on OS X Lion (with libc++) and the following compilers on CentOS 6.4 x64:

/opt/llvm/3.2/bin/clang++ -gcc-toolchain /opt/gcc/4.7.2 -std=gnu++11 foo.cc -I/opt/boost/1.53.0/include -DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT -DBOOST_SPIRIT_DEBUG
/opt/llvm/3.1/bin/clang++ -gcc-toolchain /opt/gcc/4.7.2 -std=gnu++11 foo.cc -I/opt/boost/1.53.0/include -DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT -DBOOST_SPIRIT_DEBUG
/opt/llvm/3.0/bin/clang++ -gcc-toolchain /opt/gcc/4.7.2 -std=gnu++11 foo.cc -I/opt/boost/1.53.0/include -DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT -DBOOST_SPIRIT_DEBUG
/opt/gcc/4.7.2/bin/g++ -std=gnu++11 foo.cc -I/opt/boost/1.53.0/include -DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT -DBOOST_SPIRIT_DEBUG
/opt/gcc/4.7.1/bin/g++ -std=gnu++11 foo.cc -I/opt/boost/1.53.0/include -DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT -DBOOST_SPIRIT_DEBUG

As usual, the compiler output from spirit is quite verbose, so I've included it as a gist:

The Code Follows...

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

class Object {
    public:
        void initialize(std::vector<int>) {
        }

        //void initialize() {
        //}
};

int main() {
    boost::spirit::qi::rule<std::string::iterator, int()> integer;
    boost::spirit::qi::rule<std::string::iterator, std::shared_ptr<Object>()> object;

    using boost::phoenix::bind;
    using boost::spirit::_val;
    using boost::spirit::_1;

    object  
        = (*integer) [bind(&Object::initialize, *_val, _1)];
}
È stato utile?

Soluzione

#define BOOST_SPIRIT_USE_PHOENIX_V3

Fixes it for me. And change *val to just val because phoenix will know how to bind the member function to it.


UPDATE As @llonesmiz hinted, this turns out to be related to ADL indeed. Though the relation is highly subtle.

  • Somewhere along the way, the presence of std::vector<> in the type of the member-function-pointer is making ADL search the std namespace and finding std::bind, instead of phoenix::bind.
  • Somehow, when you pass val, instead of *val, the compiler selects the phoenix bind as a better match.
  • You can see that when you have a member function that takes, say, an int (instead of a type from the std namespace), the problem disappears, and phoenix bind is always selected.

You can see the above observations by inspecting the output of this minimal test program that dumps the typeids of various bind expressions (and runs them through c++filt)



#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix.hpp>
#include <memory>

class Object {
    public:
        void initialize(std::vector<int>) {
        }
};

int main() {
    boost::spirit::qi::rule<std::string::iterator, int()> integer;
    boost::spirit::qi::rule<std::string::iterator, std::shared_ptr<Object>()> object;

    using boost::phoenix::bind;
    using boost::spirit::_val;
    using boost::spirit::_1;

    object  
        = (*integer) [bind(&Object::initialize, _val, _1)];
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top