5
votes
template<typename T, typename U = T>
struct Test{};
template<typename T>
void func(Test<T>){  //#1
}
int main(){
  func(Test<int>{});  //#2
}

It seems to no rule in the standard that mentioned what situation the default argument is required for template-parameter.

In dcl.fct.default#1

If an initializer-clause is specified in a parameter-declaration this initializer-clause is used as a default argument. Default arguments will be used in calls where trailing arguments are missing.

In this section, the rule explicitly describe when to supply default arguments for a function call. However I haven't found a quote in the standard similar with the above sentence that describes when to supply default arguments as template arguments.

Such as Test<T> at #1. Maybe at #1, the specialization would be Test<T,T>, It's just inference. However, there's no formally terminology explicitly describe this in the standard.

The only quote that implies the default arguments as template arguments is in the following rule:
temp#arg-8

When a simple-template-id does not name a function, a default template-argument is implicitly instantiated when the value of that default argument is needed. [ Example:
template<typename T, typename U = int> struct S { };
S<bool>* p; // the type of p is S<bool, int>*
The default argument for U is instantiated to form the type S<bool, int>*.  — end example ]

Consider the code at #1, Does the default argument need at #1? If it is(It seems to It need at that point because If I don't specify a default argument for template parameter U, then at the point #1 will occur an error. see godbolt outcome), According to the above quote, the default template-argument need to be implicitly instantiated, However at this point, T is a template-parameter and the definition of such function template instantiate nothing(It's just a function template definition at this point). So, How does the quote interpret this?

2
@StoryTeller-UnslanderMonica I have read that before write this question. My reading is that the quote is just about what situation the default argument will be implicitly instantiatedxmh0511
Not just. The example there is not a coincidence.StoryTeller - Unslander Monica
I do not actually. A reader of the standard is capable of understanding that the cases "when needed" includes the case where an explicit argument is not provided. It also potentially includes more (which I think is by design).StoryTeller - Unslander Monica
The function template definition does not instantiate anything. That happens later during template argument deduction at the call site. Which come to thick of it is probably why the normative text goes with "when needed".StoryTeller - Unslander Monica

2 Answers

1
votes

There is also this paragraph inside [temp.names]:

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,

So one could consider that a default-argument is needed means a default-argument is needed in order to make the template-id valid and that when there lacks a template argument, the argument is the default argument value. But I have not found anything explicit in the standard for class templates. For function template this is more explicit. Probably nobody pointed out this hole in the standard because this is a common pattern: default is used in place of what is not user provided. Maybe it will not be changed because the definition of default in the english dictionary is already given:

IT. the way that something will happen or appear automatically, especially on a computer, if you do not make any different choices -- cambrige online dictionary

0
votes

According to the above quote, the default template-argument need to be implicitly instantiated, However at this point, T is a template-parameter and the definition of such function template instantiate nothing(It's just a function template definition at this point). So, How does the quote interpret this?

The key is the difference between need of instantiation and when referenced. In the example from [temp.arg]/8, the default template argument for U is instantiated because it is needed for the instantiation of S<bool>, which unambiguously resolves to S<bool, int>. In the OP's own example, instantiation of the instantiation-dependent default template argument for U will only follow after overload resolution resolves void func(Test<T>) as the best viable overload and thus instantiates it. Just inspecting candidate overloads as part of overload resolution, however, will not lead to instantiation of any of the candidates nor any of the function template candidates parameters that are, themselves, templates. It will, however, be referencing said template parameters as part of the overload resolution process (discarding non-viable candidates).


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. [...]

For the OP's particular example, the former (instantiation) only occurs after overload resolution has finished and a best viable overload has been instantiated (which in turn instantiates the class template function argument). The latter (a function/class template specialization being referenced to), however, applies also during overload resolution, even when discarding candidates that are either not viable or not the best viable match, candidates that will never lead to instantiations.

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 [...]

and from [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.

it is clear that as part of the "end of template argument deduction", any template arguments that have not been explicitly specified will be either deduced or obtained from default arguments and substituted into the candidate function before discarding or ranking it as a viable overload. This applies without any relation to instantiation, and only in the context of a given specialization (that may not yet or ever be instantiated) being referenced, as part of overload resolution.

Finally, 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.

we note that as part of function template argument deduction for a function template parameter that is a specialization of a class template, the function template parameter type (used for deduction against an argument) includes the types referenced by the template argument list of the template parameter, meaning the particular class template specialization (function template argument) is referenced, so that, as per [temp.deduct]/1, it will go through template argument deduction and default-argument inspection for any of its template arguments that are not explicitly specified.