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

2024-11-11


2600. Type dependency of placeholder types

Section: 13.8.3.3  [temp.dep.expr]     Status: DRWP     Submitter: Hubert Tong     Date: 2022-06-18

[Accepted as a DR at the November, 2023 meeting.]

Subclause 13.8.3.2 [temp.dep.type] paragraph 7 has a list of types considered to be dependent. This list covers placeholder types only insofar as it has an entry about decltype(expression). Subclause 13.8.3.3 [temp.dep.expr] paragraph 3 has a list of expression forms not considered dependent unless specific types named by the expressions are dependent. This list includes forms where placeholder types are allowed. For example, the wording does not say that the new-expression at #1 (below) is dependent, but it ought to be:

  template <typename T> struct A { A(bool, T); };

  void g(...);

  template <typename T>
  auto f(T t) { return g(new A(t, 0)); }  // #1

  int g(A<int> *);
  int h() { return f<void *>(nullptr); }

Some implementation even treats an obviously non-dependent case as dependent:

  template <typename T, typename U> struct A { A(T, U); };

  void g(...); // #1

  template <typename T>
  auto f() { return g(new A(0, 0)); } // #1 or #2?

  int g(A<int, int> *); // #2
  void h() { return f<void *>(); }

A similar example that is non-dependent:

  template <typename T, typename U = T> struct A { A(T, U); };

  void g(...);

  template <typename T>
  auto f() { return g(new A(0, 0)); }

  int g(A<int> *);
  void h() { return f<void *>(); }

And another non-dependent one:

  template <typename T, typename U = T> struct A { A(T); };

  void g(...);

  template <typename T>
  auto f() { return g(new A(0)); }

  int g(A<int> *);
  void h() { return f<void *>(); }

And here is an example that is dependent:

  template<class T>
  struct S {
   template<class U = T> struct A { A(int); };

   auto f() { return new A(0); } // dependent return type
  };

Proposed resolution (November, 2022) [SUPERSEDED]:

  1. Change in 7.6.2.8 [expr.new] paragraph 2 as follows:

    If a placeholder type (9.2.9.7 [dcl.spec.auto]) or a placeholder for a deduced class type (9.2.9.8 [dcl.type.class.deduct]) appears in the type-specifier-seq of a new-type-id or type-id of a new-expression, the allocated type is deduced as follows: Let init be the new-initializer , if any, and T be the new-type-id or type-id of the new-expression, then the allocated type is the type deduced for the variable x in the invented declaration (9.2.9.7 [dcl.spec.auto]):
    T x init ;
    
  2. Insert new paragraphs before 13.8.3.2 [temp.dep.type] paragraph 7 and change the latter as follows:

    An initializer is dependent if any constituent expression (6.9.1 [intro.execution]) of the initializer is type-dependent. A placeholder type (9.2.9.7.1 [dcl.spec.auto.general]) is dependent if it designates a type deduced from a dependent initializer.

    A placeholder for a deduced class type (9.2.9.8 [dcl.type.class.deduct]) is dependent if

    • it has a dependent initializer or
    • any default template-argument of the primary class template named by the placeholder is dependent when considered in the scope enclosing the primary class template.

    A type is dependent if it is

    • ...
    • a function type whose exception specification is value-dependent,
    • denoted by a dependent placeholder type,
    • denoted by a dependent placeholder for a deduced class type,
    • ...

Proposed resolution (approved by CWG 2023-06-12):

  1. Change in 7.6.2.8 [expr.new] paragraph 2 as follows:

    If a placeholder type (9.2.9.7 [dcl.spec.auto]) or a placeholder for a deduced class type (9.2.9.8 [dcl.type.class.deduct]) appears in the type-specifier-seq of a new-type-id or type-id of a new-expression, the allocated type is deduced as follows: Let init be the new-initializer , if any, and T be the new-type-id or type-id of the new-expression, then the allocated type is the type deduced for the variable x in the invented declaration (9.2.9.7 [dcl.spec.auto]):
    T x init ;
    
  2. Insert new paragraphs before 13.8.3.2 [temp.dep.type] paragraph 7 and change the latter as follows:

    An initializer is dependent if any constituent expression (6.9.1 [intro.execution]) of the initializer is type-dependent. A placeholder type (9.2.9.7.1 [dcl.spec.auto.general]) is dependent if it designates a type deduced from a dependent initializer.

    A placeholder for a deduced class type (9.2.9.8 [dcl.type.class.deduct]) is dependent if

    • it has a dependent initializer, or
    • it refers to an alias template that is a member of the current instantiation and whose defining-type-id is dependent after class template argument deduction (12.2.2.9 [over.match.class.deduct]) and substitution (13.7.8 [temp.alias]).

    [ Example:

      template<class T, class V>
      struct S { S(T); };
    
      template<class U>
      struct A {
        template<class T> using X = S<T, U>;
        template<class T> using Y = S<T, int>;
        void f() {
          new X(1);    // dependent
          new Y(1);    // not dependent
        }
      };
    

    -- end example ]

    A type is dependent if it is

    • ...
    • a function type whose exception specification is value-dependent,
    • denoted by a dependent placeholder type,
    • denoted by a dependent placeholder for a deduced class type,
    • ...