Cannot infer template argument, which is a function

Why can't F print for proxy() ?

This should be possible, because I restrict it - only for functions that return int .

 #include <utility> #include <iostream> #include <type_traits> using namespace std; int foo(int bar) { cout << "int" << endl; return 2; } float foo(float bar) { cout << "float" << endl; return 1; } template <typename F, typename... Args> typename enable_if< is_same< typename result_of<F(Args...)>::type, int >::value, typename result_of<F(Args...)>::type >::type proxy(F func, Args&&... args) { return func(forward<Args>(args)...); } int main() { proxy(foo, 5); } 

Here is the error:

 b.cpp:29:17: error: no matching function for call to 'proxy(<unresolved overloaded function type>, int)' b.cpp:24:1: note: template argument deduction/substitution failed: b.cpp:29:17: note: couldn't deduce template parameter 'F' 
+6
source share
2 answers

The problem is this:

 proxy(foo, 5); 

The compiler is trying to infer the type foo , but there are 2 overloads. Of course, it can output Args... from 5 , but the type foo is still not output, since the compiler does not know which overload to choose when performing type inference.

Note that the compiler must know the type F in the function signature, i.e. here, so SFINAE does its magic:

 is_same< typename result_of<F(Args...)>::type, int >::value, 

There is absolutely no way to correctly deduce type F from a proxy(foo, 5) call proxy(foo, 5) , so SFINAE cannot go into it. As a side note, note that C ++ cannot overload only based on the return type. Thus, you cannot differentiate two functions with the same name, based only on the inverse type. You will need to somehow force the parameter mapping, which is why SFINAE will issue overloads that are not related to the candidate.

Somehow connected: Canceling the return type of an autonomous function

And the corresponding quote from the standard, underline mine (thanks @TC for pointing):

14.8.2.1 Extracting template arguments from a function call [temp.deduct.call] / (6.2)

(6) When P is a function type, a pointer to a function type or a pointer to a member function type:

  • (6.1) If the argument is an overload set containing one or more function templates, this parameter is considered as an uninduced context.

  • (6.2) If the argument is an overload set (not containing template functions), an attempted trial argument attempts to use each of the members of the set. If the deduction succeeds only for one of the set overloads, this member is used as the argument value for the deduction. If the deduction succeeds for more than one member, the overload sets the parameter to be treated as an unreduced context .

+4
source

In your example, foo calls a set of overloaded functions, and the output of the template argument cannot select one overload over the other, because they both coincide with the ranks.

Your SFINAE constraint check does not work until F is printed, so it does not help reset the float foo(float) from the set overload resolution.

Say you renamed a function that returns a float in foof , then your example will compile. But if you tried to call a proxy with foof as the function argument, the code would not compile again, this time due to the enable_if restriction.

For your example to be compiled in its current state, you must eliminate which foo you are switching to proxy

 proxy(static_cast<int(*)(int)>(foo), 5); 
+2
source

Source: https://habr.com/ru/post/988460/


All Articles