Reputation: 28659
Given two explicit
constructor overloads (based on different std::function<...>
types), the return value of std::bind
is able to select either (thereby making the call ambiguous)
call of overloaded ‘Bar(std::_Bind_helper<false, void (Foo::*)(int),
Foo*, int>::type)’ is ambiguous
If I comment out either, then the code compiles!
I would have thought making the constructors explicit
would have either selected the correct overload, or prevented both from being selected?
Of course explicitly creating a std::function
at the point I bind works:
Bar b(std::function<void(int)>(std::bind((&Foo::process), &f, 1)));
However, I'm puzzled as to why type deduction doesn't work?
std::bind
matches neither of the two constructor signatures, the fact they are explicit
should prevent both from being selected.std::bind
matches one of the two constructor signatures, the fact they are explicit
should cause the correct one to be selected.What is actually happening here?
Full working code below:
#include <functional>
struct Foo
{
void process(int) { }
};
struct Bar
{
// comment out either of these to compile
explicit Bar(std::function<void(int)>) {}
explicit Bar(std::function<void(short)>) {}
};
int main()
{
Foo f;
Bar b(std::bind(&Foo::process, &f, 1));
return 0;
}
Upvotes: 1
Views: 1538
Reputation: 153800
Making the constructor explicit
has nothing to do with the arguments having to match exactly! The affect of making a constructor explicit means that it won't be used to implicitly convert an object of a different type the type Bar
using this constructor. However, if you try to initialize a Bar
object using direct initialization (i.e., Bar(x)
), both constructors will be considered.
The result of std::bind()
is certainly not a std::function<Signature>
, i.e., it doesn't match either of your constructors exactly. Since there is a non-explicit
constructor for std::function<Signature>
which works for function objects, both signatures do match: the produced bind expression doesn't require any parameter but it can take arguments, i.e., any argument type also cannot be used to distinguish which of the two constructors of Bar
should match. Even if the bind expression would require one argument, I don't think it would be used to prefer one constructor over another.
Upvotes: 4