Question

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?

  • If the return value from std::bind matches neither of the two constructor signatures, the fact they are explicit should prevent both from being selected.
  • If the return value from 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;
}
Était-ce utile?

La solution

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top