This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115b. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-08-20


2900. Deduction of non-type template arguments with placeholder types

Section: 13.10.3.6  [temp.deduct.type]     Status: open     Submitter: Hubert Tong     Date: 2024-06-05

(From submission #546.)

The deduction rule for non-type template parameters in 13.10.3.6 [temp.deduct.type] paragraph 20seems lacking:

If P has a form that contains <i>, and if the type of i differs from the type of the corresponding template parameter of the template named by the enclosing simple-template-id, deduction fails. If P has a form that contains [i], and if the type of i is not an integral type, deduction fails. [ Footnote: ... ] ...

This wording does not address the situation when the declared type of i is a placeholder type, or when the type of the corresponding template parameter of the template named by the enclosing simple-template-id is a placeholder type.

Suggested resolution:

Change in 13.10.3.6 [temp.deduct.type] paragraph 20 as follows:

If P has a form that contains <i>, and if the type of i differs from the type deduction fails unless the type of i is the same as that of the corresponding template parameter p in the specialization (from A) of the template named by the enclosing simple-template-id, deduction fails ; if the declared type of i contains a placeholder type, the corresponding template argument for the purposes of placeholder type deduction (9.2.9.7.2 [dcl.type.auto.deduct]) is an id-expression for p. If P has a form that contains [i], and if the type of i is not an integral type, deduction fails. [ Footnote: ... ] ... [ Example 13:
  template<int i> class A { /* ... */ };
  template<short s> void f(A<s>);
  void k1() {
    A<1> a;
    f(a);      // error: deduction fails for conversion from int to short
    f<1>(a);   // OK
  }
  template<const short cs> class B { };
  template<short s> void g(B<s>);
  void k2() {
    B<1> b;
    g(b);  // OK, cv-qualifiers are ignored on template parameter types
  }

template<auto> struct C; template<long long x> void f(C<x> *); void g(C<0LL> *ap) { f(ap); // OK, deduces long long value from 0LL } template<int> struct D; template<auto x> void f(D<x> *); void g(D<0LL> *ap) { f(ap); // OK, deduces x as an int value } template<int &> struct E; template<auto x> void f(E<x> *); int v; void g(E<v> *bp) { f(bp); // error: type int of x does not match the int & type of the template parameter in the E<v> specialization of E } template<const int &> struct F; template<decltype(auto) x> void f(F<x> *); int i; void g(F<i> *ap) { f(ap); // OK, deduces x as a non-type template parameter of type const int & } template <decltype(auto)> struct G; template <auto x> long *f(G<x> *); // #1 template <decltype(auto) x> short *f(G<x> *); // #2 const int j = 0; short *g(G<(j)> *ap) { return f(ap); // OK, only #2 matches } long *g(G<j> *ap) { return f(ap); // OK, #1 is more specialized }

-- end example]