This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 118f. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-11-07
(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(); }
Proposed resolution (approved by CWG 2025-11-06):
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 8 as follows:
The component names of a template-argument-name are those of its nested-name-specifier (if any) and its identifier.
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:
- When 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 is interpreted as an 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...