Reputation: 46
I came across this compiler/language issue while working on a callback system. I'm using Visual Studio 2012. If I write:
// Works
template<typename T>
class C
{
};
C<void(int)> a1;
C<void(int, int)> a2;
void Good(C<void(int)>) { }
void Good(C<void(int, int)>) { }
void main()
{
Good(a1);
Good(a2);
}
it compiles cleanly and I verified in the debugger that the correct overloads are being called.
However, if I write:
void Foo(std::function<void(int)> fn) { }
void Foo(std::function<void(int, int)> fn) { } //<--- breaks compilation
void Bar(int a) { }
void main()
{
Foo(Bar);
}
I get the following:
>c:\dev\newtech2\src\game.cpp(389): error C2668: 'Foo' : ambiguous call to overloaded function
> c:\dev\newtech2\src\game.cpp(380): could be 'void Foo(std::function<_Fty>)'
> with
> [
> _Fty=void (int,int)
> ]
> c:\dev\newtech2\src\game.cpp(379): or 'void Foo(std::function<_Fty>)'
> with
> [
> _Fty=void (int)
> ]
> while trying to match the argument list '(overloaded-function)'
The compiler clearly knows that the two functions have different signatures due to the different template parameters, and it was able to distinguish the two in the previous example using my own template class. So is this a compiler/STL bug or some limitation in how std::function() works? Not a show-stopper but does limit one type of callback interface I wanted to provide.
Upvotes: 0
Views: 51
Reputation: 14967
In the example that works, types of the arguments a1
and a2
match exactly the corresponding parameter types of the two Good
overloads. This is not true to the second example. The selected constructor of std::function
is a function template, and has little to do with the function signature you supplied whatsoever. That is, in the eye of the compiler, to (try to) convert Bar
to std::function<void(int)>
is no better than to convert it to std::function<void(int, int)>
, despite the fact that choosing the second will ultimately lead to a compiler error (the compiler cannot foresee this anyway). One way to remedy the situation is to explicitly cast the argument Bar
to the appropriate std::function
type, or to make a convenient converter wrapper yourself to automate this procedure.
Upvotes: 1