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
Are the following examples well-formed? Note the absence of a template disambiguator:
template<typename T> class C { T::X<int> g1(); // #1 T::X<int>::Y g2(); // #2 }; template<typename T> T::X<int> h1(); // #3 template<typename T> T::X<int>::Y h2(); // #4
The return type is a type-only context per 13.8.1 [temp.res.general] paragraph 4. However, 13.3 [temp.names] paragraph 3 excludes nested-name-specifiers from the set of situations where template can be omitted. That means that #1 and #3 are valid; X is not part of a nested-name-specifier. However, #2 and #4 are invalid; the template disambiguator is missing. Those examples ought to be valid, too.
Proposed resolution (approved by CWG 2024-06-14):
Change in 13.3 [temp.names] paragraph 3 as follows:
A name is in a transitive type-only context ifA < is interpreted as the delimiter of a template-argument-list if it follows a name that is not a conversion-function-id and
- it is in a type-only context (13.8.1 [temp.res.general]) and is not the terminal name of a nested-name-specifier, or
- it is the terminal name of a nested-name-specifier that precedes a name in a transitive type-only context (possibly with an intervening template keyword).
- that follows the keyword template or a ~ after a nested-name-specifier or in a class member access expression, or
- for which name lookup finds the injected-class-name of a class template or finds any declaration of a template, or
- that is an unqualified name for which name lookup either finds one or more functions or finds nothing, or
- that is a terminal name in a using-declarator (9.9 [namespace.udecl]), in a declarator-id (9.3.4 [dcl.meaning]), or in a transitive type-only context
other than a nested-name-specifier (13.8 [temp.res]).