Created on 2025-02-03.00:00:00 last changed 5 months ago
(From submission #669.)
For the template-argument grammar in 13.3 [temp.names], there is a parsing ambiguity introduced by P2841R7 between nested-name-specifieropt template-name and type-id (via simple-type-specifier) naming a placeholder for deduced class type (9.2.9.8 [dcl.type.class.deduct]). For example:
void g(); template <typename T> struct A { static void f() { g<T::TT>((A *)0); } }; template <typename T> void g(void *); template <auto> void g(void *); template <template <typename> class> void g(void *); struct Expr { enum { TT = 0 }; }; struct Type { using TT = int; }; struct Tmpl { template <typename> struct TT; }; void h() { A<Expr>::f(); // all accept A<Type>::f(); // EDG, MSVC accept; GCC, Clang rejects A<Tmpl>::f(); // EDG, MSVC accept; GCC, Clang rejects }
P1787R6 established the direction that the template disambiguator is needed only when introducing a template-argument-list (13.3 [temp.names] paragraph 6). (Reflection made this assumption false.) All examples should be accepted.
See 13.8.2 [temp.local] for the use of an injected-class-name as a template argument.
Example:
void g(); template <typename T> struct A { static void f() { g<A>((A *)0); // all accept g<A>((A *)0, 0); // Clang, GCC, EDG accept; MSVC rejects } }; template <typename T> void g(void *); template <template <typename> class> void g(void *, int); void h() { A<int>::f(); }
Possible resolution:
Strategy: Introduce a new grammar production akin reflection-name, as a preferred option for template-argument, and say what it means in the various cases.
Change in 13.3 [temp.names] paragraph 1 as follows:
template-argument: template-argument-name constant-expression type-idnested-name-specifieropt template-namenested-name-specifier template template-nametemplate-argument-name: nested-name-specifieropt identifier nested-name-specifier template identifier
Insert a new paragraph before 13.3 [temp.names] paragraph 7 as follows:
The component names of a template-argument-name are those of its nested-name-specifier (if any) and its identifier. The terminal name of a template-argument-name of the form nested-name-specifier template identifier shall denote a template.
A template-id is valid if ...
Insert a new paragraph before 13.4.1 [temp.arg.general] paragraph 3 as follows:
If a template-argument A matches the form template-argument-name, it is interpreted as such; the identifier is looked up and its meaning is determined as follows:
- If lookup finds an injected-class-name (13.8.2 [temp.local]), then:
- If A is for a type template template parameter, A denotes the corresponding class template.
- Otherwise, it denotes a type-name.
- Otherwise, if lookup finds a template, A denotes that template.
- Otherwise, if lookup finds a type alias or a type, A denotes the underlying type and is interpreted as a type-id.
- Otherwise, A shall be a constant-expression.
In a template-argument, an ambiguity between a type-id and an expression is resolved to a type-id, regardless of the form of the corresponding template-parameter...
History | |||
---|---|---|---|
Date | User | Action | Args |
2025-02-03 00:00:00 | admin | create |