【问题标题】:Confused by a boost spirit / phoenix / C++11 interaction被boost精神/凤凰/C++11交互弄糊涂了
【发布时间】:2013-03-10 19:01:50
【问题描述】:

我已尽力减少此问题。

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

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

我尝试过在 OS X Lion(使用 libc++)上使用 stock clang 编译器,在 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)];
}

【问题讨论】:

    标签: c++ boost c++11 boost-spirit boost-phoenix


    【解决方案1】:
    #define BOOST_SPIRIT_USE_PHOENIX_V3
    

    帮我修好了。并将*val 更改为val,因为phoenix 会知道如何将成员函数绑定到它。


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

    • 在此过程中,std::vector&lt;&gt; 在成员函数指针的 type 中的存在使 ADL 搜索 std 命名空间并找到 std::bind,而不是 phoenix::bind
    • 不知何故,当您传递 val 而不是 *val 时,编译器会选择 phoenix bind 作为更好的匹配。
    • 您可以看到,当您的成员函数采用 int(而不是来自 std 命名空间的类型)时,问题就消失了,并且始终选择 phoenix bind。

    您可以通过检查 this minimal test program 的输出来查看上述观察结果,该输出转储各种绑定表达式的 typeid(并通过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)];
    }
    

    【讨论】:

    • 所以。一些想法,我确实定义了 Use_V3。我只是在命令行上做。其次,CentOS 上的 Clang 使用 libstdc++ 4.7.2 作为 C++ 库,因此这些编译器之间的 std::shared_ptr 实现应该相同。不过,在 liveworkspace 上可能并非如此,我会做一些检查。第三,即使 boost::phoenix::bind 包含一些代码来自动解压缩 shared_ptr,它不应该与它一起使用吗? 我也在做更多的工作来查看你的答案。我会在几分钟后进行跟进
    • 是的。所以看起来你是正确的,删除​​取消引用运算符几乎可以解决问题。 boost::shared_ptr 适用于 clang 和 gcc。 libstdc++ 4.7.2 的 std::shared_ptr 只能在 gcc 下工作。如果我告诉代码取消引用 shared_ptr,我仍然很困惑为什么它会失败。
    • @sharth 似乎与 ADL 有关。 This 似乎有效。
    • 好的。这就是为什么没有找到这些重载的原因。 GCC 使用 __GNUC____GNUC_MINOR__ 宏声明它是它实际使用的任何编译器。 Clang 撒谎并说它类似于 4.2.1。 Boost,然后进去说 libstdc++ 4.2.1 没有 std::shared_ptr,所以它不包括重载。
    • @llonesmiz 我确实已经确认实际上是 std::vector&lt;&gt; 参数将 std::bind 拉入关联的 ADL 命名空间。我已经用一些尝试调试 ADL 查找的 Sherlock 工作更新了答案。有谁知道“调试”ADL/重载分辨率的更好方法?
    猜你喜欢
    • 2022-01-23
    • 2019-01-12
    • 1970-01-01
    • 2014-08-14
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 2017-07-24
    • 2011-08-02
    相关资源
    最近更新 更多