This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-10-26
Subclause 13.10.3.1 [temp.deduct.general] paragraph 5 specifies:
If a template argument has not been deduced and its corresponding template parameter has a default argument, the template argument is determined by substituting the template arguments determined for preceding template parameters into the default argument. ... 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 are replaced with the corresponding deduced or default argument values.
This description is confused. We need to have already substituted into the template parameter declaration in order to finish forming a template argument, and we need to finish forming a template argument before we can substitute it into a later default template argument. Consider:
struct X { constexpr operator int() { return 0; } }; template<const int*> struct Y {}; extern int arr[]; template<typename T, T K = X(), const int *p = &arr[K], Y<p> y = {}> struct A {}; A<int> a;
Here, we need to substitute T = int into the type of K, then convert the default template argument X() to int, then substitute the converted value of p into the type of y. The substitution into template parameters and into default template arguments is necessarily interleaved.
Suggested resolution:
Change in 13.10.3.1 [temp.deduct.general] paragraph 5 as follows:
The resulting substituted and adjusted function type is used as the type of the function template for template argument deduction. For each template parameter in turn:If the function template has associated constraints (13.5.3 [temp.constr.decl]), those constraints are checked for satisfaction (13.5.2 [temp.constr.constr]). ...
- If a template argument has not been deduced and the template parameter is a parameter pack, the template argument is an empty pack.
- Otherwise,
Ifif a template argument has not been deducedand its corresponding template parameter has a default argument, the template argument is determined by substituting the template arguments determined for preceding template parameters into the default argument. If the template parameter does not have a default template argument, or if the substitution results in an invalid type, as described above, type deduction fails. [ Example: ... ]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 are replaced with the corresponding deduced or default argument values.The substituted template parameter is determined by substituting the template arguments determined for preceding template parameters into the template parameter. If the substitution results in an invalid type, as described above, type deduction fails.- The template argument is matched against the substituted template parameter (13.4.1 [temp.arg.general]). If the template argument does not match the substituted template parameter, type deduction fails. [ Note: Matching a template argument to a non-type template parameter may perform a conversion. The converted value is used for later substitutions. -- end note ]