In this example a function is passed to an implicitly instantiated function template.
// Function that will be passed as argument
int foo() { return 0; }
// Function template to call passed function
template<typename F>
int call(F f) {
return f();
}
template<typename F, typename A>
int call(F f, A a) {
return f(a);
}
int a = call(foo);
We can break this code by adding an overload for foo()
.
int foo(int i) { return 0; }
The name "foo
" is now ambiguous and the example will no longer compile. This can be made to compile by explicitly providing function pointer type info.
int (*func_takes_void)() = foo;
int a = call(func_takes_void);
int (*func_takes_int)(int) = foo;
int b = call(func_takes_int, 0);
http://coliru.stacked-crooked.com/a/e08caf6a0ac1e6b9
Is it possible to instead deduce the function pointer types? If so, why does my attempt below not work and what is the right way to do this?
If this is not possible, a good answer would explain why.
Attempt thus far
A human can see which foo()
is intended in the two calls by inspecting the definitions of call<>()
but that info is not available to the compiler for overload resolution. Still, the information is all there, it just needs to be pulled into the function template signature. This may be possible with expression SFINAE.
In pseudo code we want this:
template<IgnoreThis, typename ReturnType>
struct expr_check
{
typedef ReturnType type;
}
template<typename F>
expr_check<expression requiring F have correct signature, result_of<F>::type>::type
call(F f);
Here is that idea worked out in real code.
http://coliru.stacked-crooked.com/a/a3ce828d6cb16c2d
The function template signatures are:
template<typename F>
typename expr_check<sizeof(declval<F>()()), typename func_ptr_result<F>::type>::type
call(F f);
template<typename F, typename A>
typename expr_check<sizeof(declval<F>()(declval<A>())), typename func_ptr_result<F>::type>::type
call(F f, A a);
What I currently have does not compile. From the compiler output you can see that on both attempts to instantiate the function template there is substitution failure on one call<>()
overload and the other simply gives an opaque "couldn't deduce template parameter".
(The colirus were compiled as C++03 but C++11 answers are fine.)
My suspicion is that while instantiating call<>()
, foo()
is not being called and C++ simply does not provide for overload resolution of foo()
in this context. It doesn't matter that it can be proven that one foo()
overload is the correct one, C++ just doesn't mandate overload resolution here. On the other hand, overload resolution isn't limited to a function being called. A function pointer of appropriate type gets to select overloads of foo()
.
Related questions
There are a few questions asking about overloading on function pointer type. It looks like this can't be done. I didn't find any questions trying to do this through expression SFINAE.
This seems to be the closest related question.
Is there a way to deduce the value of a function pointer template parameter?
Bonus pedantry
Is "function pointer" the correct phrase to have used in the title? Would "function reference" have been more accurate?