Consider the following code:
template <typename>
struct S { };
void g(S<int> t);
template <typename T>
void f(T, std::function<void(S<T>)>);
When attempting to invoke
f(0, g);
I get the following error:
error: no matching function for call to 'f' f(0, g); ^ note: candidate template ignored: could not match 'function<void (S<type-parameter-0-0>)>' against 'void (*)(S<int>)' void f(T, std::function<void(S<T>)>); ^
While I understand that generally the type of the std::function
parameter can't be deduced as it is a non-deduced context
In this case T
can first be deduced by the passed argument 0
, and then substituted into std::function<void(S<T>)>
to get std::function<void(S<int>)>
.
I would expect that after deducing T=int
, the compiler would substitute T
everywhere in the signature and then attempt to construct the std::function
parameter with the argument g
.
Why is that not the case? I presume that the ordering in which substitution/deduction happens has something to do with this, but I'd like to see the relevant Standard wording.
Bonus question: is this something that could potentially be changed in a future Standard while preserving backwards compatibility, or is there a fundamental reason why this kind of substitution doesn't work?
It is not a non-deduced context. Quite the contrary. Because deduction for the parameter of
std::function
is attempted, but the argument is not astd::function
, deduction fails. The deduction of template arguments from function arguments must agree for all function arguments. If it fails for one, it fails entirely.Making the type of the second function parameter into a non-deduced context is actually how one can overcome the error.
T
is deduced successfully from the first function argument, and there is nothing left to deduce. So the dedcution is deemed a success.Live
This is not true.
T
is deduceable in this context. If you change the code tothe code would compile and
T
is correctly deduced.Your issue is that you are passing an object to the function that it can't extract
T
from. The compiler will not do any conversion of the function arguments when it tries to deduceT
. That means you have aint
and a function as the types passed to the function. It getsint
from0
, then tries to get the type from thestd::function
you pass in the second parameter but since you didn't pass astd::function
it can't extractT
and because of that, you get an error.