The problem is that both function<int()> and function<int(int)> are constructive from the same function. Here's what the std::function constructor declaration looks like in VS2010:
template<class _Fx> function(_Fx _Func, typename _Not_integral<!_Is_integral<_Fx>::value, int>::_Type = 0);
Ignoring the SFINAE part, it is constructive from anything.
std::/boost::function use a method called type erasure to allow the transfer of harsh objects / functions, so that they satisfy the signature for a long time when called. One of the drawbacks is that you get an error in the deepest part of the implementation (where the save function is called) when delivering an object that cannot be called, as required for its signature, and not in the constructor.
The problem can be illustrated by this small class:
template<class Signature> class myfunc{ public: template<class Func> myfunc(Func a_func){
Now that the compiler is looking for valid functions for the overload set, it tries to convert the arguments if there is no perfect fitting function. The conversion can occur through the constructor of the function parameter or through the conversion operator of the argument specified by the function. In our case, this is the first.
The compiler is trying to perform the first overload a . To make it viable, he must make a transformation. To convert a int(*)() to myfunc<int()> , he tries to create the myfunc constructor. As a template that accepts something, the transformation naturally succeeds.
Now he is trying to do the same with the second overload. The constructor still remains the same and still takes something that is given to it, the conversion also works.
Left with two functions in the overload set, the compiler is a sad panda and does not know what to do, so it just says that the call is ambiguous.
So, at the end, the Signature part of the template is type when creating declarations / definitions, but not when you want to build an object.
Edit :
With all my attention, answering the title question, I completely forgot about your second question :(
Can I get around this or do I have to keep (annoying) explicit ghosts?
Afaik, you have 3 options.
- Keep the cast
Make a function object of the appropriate type and pass it
function<int()> fx = x; function<int(int)> fy = y; a(fx); a(fy);
Hide tedious casting in functions and use TMP to get the correct signature
The TMP version (metaprogramming template) is rather verbose and has boilerplate code, but hides casting from the client. An example version can be found here , which is based on the get_signature metafile, which partially specializes in types of function pointers (and gives a good example of how pattern matching can work in C ++):
template<class F> struct get_signature; template<class R> struct get_signature<R(*)()>{ typedef R type(); }; template<class R, class A1> struct get_signature<R(*)(A1)>{ typedef R type(A1); };
Of course, this needs to be expanded for the number of arguments that you want to support, but this is done once and then buried in the header "get_signature.h" . :)
Another option that I consider, but immediately discarded, was SFINAE, which would present even more boilerplate code than the TMP version.
So yes, these are the options that I know of. Hope one of them works for you. :)