[英]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.