繁体   English   中英

带有提升的C ++ 11占位符

[英]C++11 placeholders with boost

这段代码......

int main()
{
    using namespace std::placeholders;
    ClassA a;
    ClassB b, b2;
    a.SigA.connect( std::bind(&ClassB::PrintFoo, &b) );
    a.SigB.connect( std::bind(&ClassB::PrintInt, b,  _1));
    a.SigB.connect( std::bind(&ClassB::PrintInt, &b2, _1));

    a.SigA();
    a.SigB(4);
}

给出编译错误,“错误:引用'_1'是不明确的”

它可以通过完全限定占位符来修复...

int main()
{
    // using namespace std::placeholders;
    ClassA a;
    ClassB b, b2;
    a.SigA.connect( std::bind(&ClassB::PrintFoo, &b) );
    a.SigB.connect( std::bind(&ClassB::PrintInt, b,  std::placeholders::_1));
    a.SigB.connect( std::bind(&ClassB::PrintInt, &b2, std::placeholders::_1));

    a.SigA();
    a.SigB(4);
}

...但为什么第一个代码片段不起作用?

编辑

为了防止任何歧义,我正在使用--stdlib=libc++ -std=c++0x编译Clang和Boost 1.52,整个代码块就是这个......

#include <boost/signals2.hpp>
#include <iostream>

struct ClassA
{
    boost::signals2::signal<void ()>    SigA;
    boost::signals2::signal<void (int)> SigB;
};

struct ClassB
{
    void PrintFoo()      { std::cout << "Foo" << std::endl; }
    void PrintInt(int i) { std::cout << "Bar: " << i << std::endl; }
};

int main()
{
    // using namespace std::placeholders;
    ClassA a;
    ClassB b, b2;
    a.SigA.connect( std::bind(&ClassB::PrintFoo, &b) );
    a.SigB.connect( std::bind(&ClassB::PrintInt, b,  std::placeholders::_1));
    a.SigB.connect( std::bind(&ClassB::PrintInt, &b2, std::placeholders::_1));

    a.SigA();
    a.SigB(4);
}

让我们看看包含的工作原理:

#include <boost/signals2.hpp>包括#include <boost/signals2/signal.hpp> ,其中包括#include <boost/signals2/slot.hpp> ,其中包括#include <boost/bind.hpp> ,其中包括#include <boost/bind/bind.hpp>包括include <boost/bind/placeholders.hpp> ,它使用static boost::arg<1> _1; *在全局命名空间中,因此含糊不清。

*:从技术上讲, _1在一个未命名的命名空间中,但由于using指令而可见。

一种解决方法是在文件顶部定义以下内容,以便不包含<boost/bind/placeholders.hpp>

#define BOOST_BIND_NO_PLACEHOLDERS

C ++看到两个名为_1全局标识符。 你不知道你的意思是std::placeholders::_1而不是Boost的_1 这是标准库将它们放入嵌套命名空间的原因之一:防止像这样的意外冲突。

如果您需要缩短它们,只需创建一个简单的命名空间别名:

namespace ph = std::placeholders

那就是ph::_1

GCC提供有关您的错误的以下信息:

.../include/c++/4.7.0/functional:864:34: \
    error: candidates are: const std::_Placeholder<1> std::placeholders::_1
.../boost/1.49.0/boost/bind/placeholders.hpp:55:15: \
    error:                 boost::arg<1> {anonymous}::_1

可以在第二个错误中找到问题的提示: boost::arg<1> {anonymous}::_1

原因是boost占位符位于全局命名空间内的匿名命名空间中。

namespace
{
    boost::arg<1> _1;
    // etc...
} // unnamed namespace

由于boost占位符位于匿名命名空间中,并且您将std::placeholders导入全局命名空间,因此它们现在都可在全局范围内使用。

因此,编译器无法知道您指的是哪个符号。

正如Nicol建议的那样,使用命名空间别名std::placeholders::_1创建一个简写前缀以减少输入。

由于您使用的是std::bind我认为您有一些C ++ 11支持。 也考虑这个版本(即首选lambdas而不是std::bind

int main()
{
    ClassA a;
    ClassB b, b2;
    a.SigA.connect( [&](){ b.PrintFoo(); } );
    a.SigB.connect( [&](int i){ b.PrintInt(i); } );
    a.SigB.connect( [&](int i){ b2.PrintInt(i); } );

    a.SigA();
    a.SigB(4);
}

通过使用局部变量在范围内的另一个解决方法:

{
    auto& _1 = std::placeholders::_1;
    auto f = std::bind(&Foo::bar, b, _1);
    ...
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM