Substitution failure with `std::function` and previously deduced template parameter - why? - c++

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>)>);
^
live example on godbolt.org
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?

While I understand that generally the type of the std::function parameter can't be deduced as it is a non-deduced context.
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 a std::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.
[temp.deduct.type]
2 In some cases, the deduction is done using a single set of
types P and A, in other cases, there will be a set of corresponding
types P and A. Type deduction is done independently for each P/A pair,
and the deduced template argument values are then combined. If type
deduction cannot be done for any P/A pair, or if for any pair the
deduction leads to more than one possible set of deduced values, or if
different pairs yield different deduced values, or if any template
argument remains neither deduced nor explicitly specified, template
argument deduction fails.
Making the type of the second function parameter into a non-deduced context is actually how one can overcome the error.
#include <functional>
template<typename T>
struct type_identity {
using type = T;
};
template <typename>
struct S { };
void g(S<int> ) {}
template <typename T>
void f(T, typename type_identity<std::function<void(S<T>)>>::type) {}
int main() {
f(0, g);
}
T is deduced successfully from the first function argument, and there is nothing left to deduce. So the dedcution is deemed a success.
Live

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.
This is not true. T is deduceable in this context. If you change the code to
template <typename T>
void f(std::function<void(S<T>)>);
int main()
{
f(std::function<void(S<int>)>(g));
}
the 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 deduce T. That means you have a int and a function as the types passed to the function. It gets int from 0, then tries to get the type from the std::function you pass in the second parameter but since you didn't pass a std::function it can't extract T and because of that, you get an error.

Related

Why does the compiler try to deduce when an argument-less function template is provided?

template <typename... T>
struct X {
static_assert(sizeof...(T) != 0);
};
template <typename... T>
void f(const X<T...> &) {}
template <typename T>
void inner() {}
int main() {
f(inner);
}
The static assert fires in this example.
Why does the compiler try to deducing anything here? And then it apparently even tries to instantiate X (with empty type argument list?..)...
Why the error isn't just 'template used without arguments'?..
If I change inner function to be a struct, the compiler reports:
use of class template 'inner' requires template arguments
which makes sense; if the param is just const X &, there's
declaration type contains unexpanded parameter pack 'T'
which also makes sense, however is less clear than the case with struct, because it reports an issue at the callee, not at the call site.
If the param is const X<T> &, the report is also a bit weird at first sight:
candidate template ignored: couldn't infer template argument 'T'.
These errors are for Clang 14, but GCC also reports similar ones.
Is the instantiation here somehow specified by the standard? If so, how? Also, why does it result in an empty type list?
This is mostly due to [temp.arg.explicit]/4, applicable when source names a function template, and emphasis mine:
Trailing template arguments that can be deduced or obtained from default template-arguments may be omitted from the list of explicit template-arguments. A trailing template parameter pack not otherwise deduced will be deduced as an empty sequence of template arguments. If all of the template arguments can be deduced, they may all be omitted; in this case, the empty template argument list <> itself may also be omitted.
The function template name as an argument means it is not used for template argument deduction of f ([temp.deduct.type]/(5.5.3)). So the pack T is not deduced from the function argument list (inner), and [temp.arg.explicit]/4 applies and deduces T as an empty list of types.
Now to evaluate the expression f(inner) involves converting the expression inner to the parameter type const X<>&. Whether and how this is valid depends on the constructors of class X<>, so the template is instantiated, causing the static_assert error since the template parameter pack does have zero elements.
Because the argument refers to an overload set that contains a function template X, no deduction is attempted from it. The hope is that the deduction will succeed anyway (perhaps from other arguments) and then the template arguments of X can be deduced from the resulting argument type. (Of course, it’s impossible to deduce the template argument for inner, but even that of
template<class T>
T make();
can be deduced in certain contexts, so it’s not in general a vain hope.)
Here, deduction for f does succeed vacuously, with T as an empty pack. (This is much like a default template argument.) Then const X<>& is the parameter type, and so overload resolution is attempted to construct an X<> from inner. That obviously depends on the constructors for X<>, so that type is completed and the compilation fails.

How does the template argument deduction perform for function template parameter when it is a class template with default argument

template<typename T, typename U = T>
struct Test{};
template<typename T>
void func(Test<T>){ //#1
}
int main(){
func(Test<int>{}); //#2
}
Consider the above code, At the point of invocation of function template func, the type of argument is Test<int,int>, When call the function template, template argument deduction will perform.
The rule of template argument deduction for function call is :
temp.deduct#call-1
Template argument deduction is done by comparing each function template parameter type (call it P) that contains template-parameters that participate in template argument deduction with the type of the corresponding argument of the call (call it A) as described below.
I'm pretty sure the type of A is Test<int,int>, however I'm not sure what the type of P here is. Is it Test<T> or Test<T,T>, According to the rule, It seems to the type of P here is Test<T>, then deduction process is performed to determine the value of T that participate in template argument deduction. Then according to these rules described as the following:
temp.deduct#call-4
In general, the deduction process attempts to find template argument values that will make the deduced A identical to A (after the type A is transformed as described above).
temp.deduct#5
When all template arguments have been deduced or obtained from default template arguments, all uses of template parameters in the template parameter list of the template and the function type are replaced with the corresponding deduced or default argument values.
Because the class template Test has a default argument, hence the deduced T is substituted into default argument. That means the deduced A is Test<int,int> and it is identical to Argument type Test<int,int>.
However, It's just my understanding. I'm not sure what type the P here is. If change the type of function argument to Test<int,double>, the outcome will report:
candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'double')
The outcome looks like as if the P is Test<T,T> and the fist value of T is conflicting with the second value of T.
So, My question is:
Whether the P here is Test<T> or Test<T,T>? and why?
not a language lawyer answer
There is no type Test<T> is actually a "shorthand" for Test<T, T>.
Just like with default function arguments if you have int foo(int a, int b = 24) the type of the function is int (int, int) and any call like foo(11) is actually foo(11, 24).
P must be a type not a template. test <T> is a template-id, but it is not explicitly said in the standard that the template-id test <T> is equivalent to test<T,T>. The only thing that is said is:
A template-id is valid if
[...]
there is an argument for each non-deducible non-pack parameter that does not have a default template-argument, [...]
After that, holes in the standard are filled by our intuition oriented by the use of the term default.
I think the key point here is that a template designate a family, and a template-id cannot designate a family.
Whether the P here is Test<T> or Test<T,T>? and why?
P is Test<T,T>.
I think we can agree that the rules of [temp.deduct] applies also for class templates; e.g. [temp.class.order], covering partial ordering of class template specializations, is entirely based on the concept of re-writing the class templates to (invented) function templates and applying the rules of function templates to that of the invented function templates corresponding to the original class templates under partial ordering analysis. Combined with the fact that the standard passage for class templates is quite brief in comparison to function templates, I interpret the references below as applying also for class templates.
Now, from [temp.deduct]/1 [emphasis mine]:
When a function template specialization is referenced, all of the template arguments shall have values. The values can be explicitly specified or, in some cases, be deduced from the use or obtained from default template-arguments. [...]
and, from [temp.deduct]/2 [emphasis mine]:
When an explicit template argument list is specified, the template arguments must be compatible with the template parameter list and must result in a valid function type as described below; otherwise type deduction fails. Specifically, the following steps are performed when evaluating an explicitly specified template argument list with respect to a given function template:
(2.1) The specified template arguments must match the template parameters in kind (i.e., type, non-type, template). There must not be more arguments than there are parameters unless [...]
With extra emphasis on "is referenced" and "the specified template arguments"; there is no requirement that we specify all arguments for a given matching function(/class) template, only that those that do specify follow the requirements of [temp.deduct]/2 for explicitly specified template arguments.
This leads us to back to [temp.deduct]/1 for the remaining template arguments of a given candidate function/class template: these can be either deduced (function templates) or obtained from the default template arguments. Thus, the call:
func(Test<int>{});
is, as per the argument above, semantically equivalent to
func(Test<int, int>{});
with the main difference that the template arguments for the former is decided by both an explicitly specified template arguments and a default template argument, whereas for the latter both are decided by explicitly specified template arguments. From this, it is clear that A is Test<int, int>, but we will use a similar argument for P.
From [temp.deduct.type]/3 [emphasis mine]:
A given type P can be composed from a number of other types, templates, and non-type values:
[...]
(3.3) A type that is a specialization of a class template (e.g., A<int>) includes the types, templates, and non-type values referenced by the template argument list of the specialization.
Notice that the description in [temp.deduct.type]/3.3 now returns to the template argument list of the template type P. It doesn't matter that P, for when inspecting this particular candidate function in overload resolution, refers to a class template by partly explicitly specifying the template argument list and partly relying on a default template parameter, where the latter is instantiation-dependent. This step of overload resolution does not imply any kind of instantiation, only inspection of candidates. Thus, the same rules as we just applied to the template argument A above applies to P, in this case, and as Test<int, int> is referenced (via Test<int>), P is Test<int, int>, and we have a perfect match for P and A (for the single parameter-argument pair P and A of this example)
Compiler error messages?
Based in the argument above, one could arguably expect a similar error message for the OP's failing example:
// (Ex1)
template<typename T, typename U = T>
struct Test{};
template<typename T>
void func(Test<T>) {}
int main() {
func(Test<int, double>{});
}
as for the following simple one:
// (Ex2)
struct Foo {};
template<typename T> struct Test {};
template<typename T> void f(T) {}
int main() {
f<Test<int>>(Test<Foo>{});
}
This is not the case, however, as the former yields the following error messages for GCC and Clang, respectively:
// (Ex1)
// GCC
error: no matching function for call to 'func(Test<int, double>)'
note: template argument deduction/substitution failed:
deduced conflicting types for parameter 'T' ('int' and 'double')
// Clang
error: no matching function for call to 'func'
note: candidate template ignored: deduced
conflicting types for parameter 'T' ('int' vs. 'double')
whereas the latter yields the following error messages for GCC and Clang, respectively:
// (Ex2)
// GCC
error: could not convert 'Test<Foo>{}' from 'Test<Foo>' to 'Test<int>'
// Clang
error: no matching function for call to 'f'
note: candidate function template not viable:
no known conversion from 'Test<Foo>' to 'Test<int>' for 1st argument
We can finally note that if we tweak (Ex1) into explicitly specifying the single template argument of f, both GCC and Clang yields similar error messages as for (Ex2), hinting that argument deduction has been entirely removed from the equation.
template<typename T, typename U = T>
struct Test{};
template<typename T>
void func(Test<T>) {}
int main() {
func<int>(Test<int, double>{});
}
The key for this difference may be as specified in [temp.deduct]/6 [emphasis mine]:
At certain points in the template argument deduction process it is necessary to take a function type that makes use of template parameters and replace those template parameters with the corresponding template arguments. This is done at the beginning of template argument deduction when any explicitly specified template arguments are substituted into the function type, and again at the end of template argument deduction when any template arguments that were deduced or obtained from default arguments are substituted.
namely that the template argument deduction process is separated into a clear beginning and end, categorizing:
explicitly specified template arguments as the beginning of the process, and,
deduced or default argument-obtained template arguments as the end of the process,
which would explain the differences in the error messages of the examples above; if all template arguments have been explicitly specified in the beginning of the deduction process, the remainder of the process will not have any remaining template argument to work with w.r.t. deduction or default template arguments.
I tryed to come up with a code that forces only class deduction without function deduction.
Here, there are no function instantiations, but the compiler emits an error anyway:
template<typename T, typename U = T>
struct Test{};
template<typename T>
void func(Test<T, T>){
}
template<typename T>
void func(Test<T>){
}
redefinition of 'template<class T> void func(Test<T, T>)'
GCC: https://godbolt.org/z/7c981E
Clang:
https://godbolt.org/z/G1eKTx
Previous wrong answer:
P refers to template parameter, not to template itself. In declaration Test<typename T, typename U = T> P refers to T, not to Test. So in the instantiation Test<int> T is int, just like A in the call is also int.

Partial ordering on T*... and const T&

cppreference claims the following
template <class ...T> int f(T*...); // #1
template <class T> int f(const T&); // #2
f((int*)0); // OK: selects #1
// (was ambiguous before DR1395 because deduction failed in both directions)
If we follow DR1395 we see
If A was transformed from a function parameter pack and P is not a parameter pack, type deduction fails. Otherwise, using Using the resulting types P and A, the deduction is then done as described in 17.9.2.5 [temp.deduct.type]. If P is a function parameter pack, the type A of each remaining parameter type of the argument template is compared with the type P of the declarator-id of the function parameter pack. Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack. Similarly, if A was transformed from a function parameter pack, it is compared with each remaining parameter type of the parameter template. If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template.
[...]
If, after considering the above, function template F is at least as specialized as function template G and vice-versa, and if G has a trailing paramter pack for which F does not have a corresponding parameter, and if F does not have a trailing parameter pack, then F is more specialized than G.
From what I can infer, this means we should be matching each individual type expanded from T*... to const T& and vice versa. In this case, T* is more specialized than const T& (T from U* succeeds, T* from U fails).
However, the compilers disagree. Clang thinks it's ambiguous and gcc thinks the second should be called, both of which differs from cppreference.
What is the correct behaviour?
cppreference is correct for this example (which is exactly the example from the CWG issue, as well as CWG 1825). Let's go through the deduction both ways.
Deduce template <class ...T> int f(T*...); from const U&. This fails, not going to be able to deduce T* from const U& - the fact that it's a pack here is immaterial. So #2 is not at least as specialized as #1.
Deduce template <class T> int f(const T&); from U*... We used to have the rule "If A was transformed from a function parameter pack and P is not a parameter pack, type deduction fails." - which would have meant that we failed before we even tried to do anything else. But CWG 1395 removed that sentence, so we keep going, and we have the new sentence:
Similarly, if A was transformed from a function parameter pack, it is compared with each remaining parameter type of the parameter template.
We compare U*, by itself, to each remaining parameter type, which is const T&. That deduction succeeds. So #1 is at least as specialized as #2.
As a result, now #1 is more specialized than #2. The quote you cite about trailing parameter packs as a later tiebreaker doesn't apply - since we don't have the case where each function template is at least as specialized as the other. Also the other quote you cite ([temp.deduct.type]/10 is about deducing function types, so I don't think it applies here either? Although I'm also not sure about the example in that section - or what that particular rule actually means.

Type deduction for non-viable function templates

In his answer to this question and the comment section, Johannes Schaub says there's a "match error" when trying to do template type deduction for a function template that requires more arguments than have been passed:
template<class T>
void foo(T, int);
foo(42); // the template specialization foo<int>(int, int) is not viable
In the context of the other question, what's relevant is whether or not type deduction for the function template succeeds (and substitution takes place):
template<class T>
struct has_no_nested_type {};
// I think you need some specialization for which the following class template
// `non_immediate_context` can be instantiated, otherwise the program is
// ill-formed, NDR
template<>
struct has_no_nested_type<double>
{ using type = double; };
// make the error appear NOT in the immediate context
template<class T>
struct non_immediate_context
{
using type = typename has_no_nested_type<T>::type;
};
template<class T>
typename non_immediate_context<T>::type
foo(T, int) { return {}; }
template<class T>
bool foo(T) { return {}; }
int main()
{
foo(42); // well-formed? clang++3.5 and g++4.8.2 accept it
foo<int>(42); // well-formed? clang++3.5 accepts it, but not g++4.8.2
}
When instantiating the first function template foo for T == int, the substitution produces an invalid type not in the immediate context of foo. This leads to a hard error (this is what the related question is about.)
However, when letting foo deduce its template-argument, g++ and clang++ agree that no instantiation takes place. As Johannes Schaub explains, this is because there is a "match error".
Question: What is a "match error", and where and how is it specified in the Standard?
Altenative question: Why is there a difference between foo(42) and foo<int>(42) for g++?
What I've found / tried so far:
[over.match.funcs]/7 and [temp.over] seem to describe the overload resolution specifics for function templates. The latter seem to mandate the substitution of template parameters for foo.
Interestingly, [over.match.funcs]/7 triggers the process described in [temp.over] before checking for viability of the function template (specialization).
Similarly, type deduction does not to take into account, say, default function arguments (other than making them a non-deduced context). It seems not to be concerned with viability, as far as I can tell.
Another possibly important aspect is how type deduction is specified. It acts on single function parameters, but I don't see where the distinction is made between parameter types that contain / are dependent on template parameters (like T const&) and those which aren't (like int).
Yet, g++ makes a difference between explicitly specifying the template parameter (hard error) and letting them be deduced (deduction failure / SFINAE). Why?
What I've summarized is the process described at 14.8.2.1p1
Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below.
In our case, we have for P (T, int) and for A, we have (int). For the first pair of P/A, which is T against int, we can match T to int (by the process described in 14.8.2.5). But for the second "pair", we have int but have no counterpart. Thus deduction cannot be made for this "pair".
Thereby, by 14.8.2.5p2, "If type deduction cannot be done for any P/A pair, ..., template
argument deduction fails.".
You then won't ever come to the point where you substitute template arguments into the function template.
This can all probably described more precisely in the Standard (IMO), but I believe this is how one could implement things to match the actual behavior of Clang and GCC and it seems a reasonable interpretation of the Standardese.

template function call with empty angle brackets <>

I am confused with the below template behavior, where it compiles fine with the empty angle brackets (template without parameters) since syntactically, template<> is reserved to mark an explicit template specialization.
template <typename T> void add(T a, T b) { }
int main() {
add<>(10, 3); // compiles fine since both parameters are of same data type
add<>(10, 3.2); // Error: no matching function for call to add(int, double)
}
In the above case is the template parameter really optional?
template<> is reserved to mark an explicit template specialization.
It means various things, depending on context. Here it means "use the default or deduced argument", just as if you simply said add.
In the first case, both function arguments have the same type, so the template argument can be deduced as int.
In the second case, they have different types, so the template argument can't be deduced. You'd have to specify what you want, e.g. add<double>, convert one function argument to match the other, or modify the template to parametrise each type separately.
In the above case is the template parameter really optional?
Yes, if it can be deduced from the argument types.
In the first case, yes because the can be inferred through the standard's rules. In the second, no because they can't - you'd have to write something like:
add<float>(10, 3.2);
You have a single template parameter and two function parameters of different types. Template argument deduction needs to match for both arguments, but if you supply an int and a double, it doesn't work. The reason is that deduced argument have to an exact match and type conversions are not considered.
The syntax
add<double>(10, 3.2);
would explicitly force T to be equal to double. In that case, the int constant 10 is converted to double.
You could also add another overload
template <typename T, typename U> void add(T a, U b) { }
and possibly constrain that using SFINAE by requiring that is_convertible<T, U>