Created on 2022-06-18.00:00:00 last changed 7 months ago
Proposed resolution (approved by CWG 2023-06-12):
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 ;
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,
- ...
Proposed resolution (November, 2022) [SUPERSEDED]:
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 ;
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,
- ...
[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
};
History | |||
---|---|---|---|
Date | User | Action | Args |
2024-04-05 21:43:46 | admin | set | status: dr -> drwp |
2023-12-19 10:15:28 | admin | set | status: ready -> dr |
2023-11-10 14:27:11 | admin | set | status: tentatively ready -> ready |
2023-06-13 16:05:19 | admin | set | status: review -> tentatively ready |
2023-02-11 23:38:57 | admin | set | messages: + msg7195 |
2022-11-25 05:14:04 | admin | set | status: tentatively ready -> review |
2022-11-11 09:44:52 | admin | set | status: review -> tentatively ready |
2022-11-11 09:44:52 | admin | set | status: review -> review |
2022-11-11 09:44:52 | admin | set | status: review -> review |
2022-11-11 09:44:52 | admin | set | status: review -> review |
2022-11-11 09:41:00 | admin | set | status: tentatively ready -> review |
2022-11-11 09:41:00 | admin | set | status: tentatively ready -> tentatively ready |
2022-11-11 09:41:00 | admin | set | status: tentatively ready -> tentatively ready |
2022-11-11 09:41:00 | admin | set | messages: + msg7000 |
2022-11-11 09:41:00 | admin | set | status: open -> tentatively ready |
2022-06-18 00:00:00 | admin | create |