2

我尽量减少这个问题。

如果我取消注释void initialize(),则此代码将编译。如果我将其注释掉,则它不会构建。

我发现解决此问题的唯一方法是使用 C++03 模式构建,boost::shared_ptr而不是std::shared_ptr.

我曾尝试使用 OS X Lion 上的股票 clang 编译器(使用 libc++)和 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

像往常一样,spirit 的编译器输出非常冗长,因此我将其作为要点包含在内:

代码如下...

#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)];
}
4

1 回答 1

2
#define BOOST_SPIRIT_USE_PHOENIX_V3

为我修复它。并更改*val为只是val因为 phoenix 将知道如何将成员函数绑定到它。


更新正如@llonesmiz 暗示的那样,这确实与 ADL 有关。虽然关系非常微妙。

  • 在此过程中,成员函数指针类型std::vector<>中的存在使 ADL 搜索 std 命名空间并找到,而不是.std::bindphoenix::bind
  • 不知何故,当您通过val, 而不是 时*val,编译器会选择 phoenixbind作为更好的匹配。
  • 你可以看到,当你有一个成员函数,比如说,一个int(而不是来自std命名空间的类型)时,问题就消失了,并且总是选择 phoenix bind。

您可以通过检查这个最小测试程序的输出来查看上述观察结果,该程序转储各种绑定表达式的类型标识(并运行它们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)];
}
于 2013-03-10T19:08:17.383 回答