This code ...
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);
}
Gives the compilation error, "error: reference to '_1' is ambiguous"
It can be fixed by fully qualifying the placeholders ...
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);
}
...but why doesn't the first code snippet work?
EDIT
Just to prevent any ambiguity, I am compiling with Clang and Boost 1.52 with --stdlib=libc++ -std=c++0x
and the entire code block is this ...
#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);
}
The objects _1, _2, ... _N are placeholders that represent the first, second, ..., through Nth argument, respectively in a function call to an object returned by bind . For example, you use _6 to specify where the sixth argument should be inserted when the bind expression is evaluated.
_1 is a placeholder. Boost. Bind defines placeholders from _1 to _9 . These placeholders tell boost::bind() to return a function object that expects as many parameters as the placeholder with the greatest number.
boost::bind is a generalization of the standard functions std::bind1st and std::bind2nd. It supports arbitrary function objects, functions, function pointers, and member function pointers, and is able to bind any argument to a specific value or route input arguments into arbitrary positions.
Let's see how the includes work:
#include <boost/signals2.hpp>
includes #include <boost/signals2/signal.hpp>
which includes #include <boost/signals2/slot.hpp>
which includes #include <boost/bind.hpp>
which includes #include <boost/bind/bind.hpp>
which includes include <boost/bind/placeholders.hpp>
, which uses static boost::arg<1> _1;
* in the global namespace, hence the ambiguity.
*: Technically, _1
is in an unnamed namespace, but it visible due to a using directive.
One workaround is define the following at the top of your file so that <boost/bind/placeholders.hpp>
is not included:
#define BOOST_BIND_NO_PLACEHOLDERS
C++ sees two global identifiers named _1
. It has no idea that you mean std::placeholders::_1
instead of Boost's _1
. This is one of the reasons why the standard library puts them in a nested namespace: to prevent accidental conflicts like this.
If you need them to be shorter, just create a simple namespace alias:
namespace ph = std::placeholders
Then it's just ph::_1
.
GCC give the following information regarding your error:
.../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
The hint to the problem can be found in the 2nd error: boost::arg<1> {anonymous}::_1
The cause is that the boost placeholders are in an anonymous namespace within the global namespace.
namespace
{
boost::arg<1> _1;
// etc...
} // unnamed namespace
Since the boost placeholders are in an anonymous namespace and you're importing std::placeholders
into the global namespace, they are now both available in the global scope.
As such there is no way for the compiler to know which symbol you are referring to.
As Nicol suggests, use a namespace alias to create a shorthand prefix to std::placeholders::_1
to reduce the typing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With