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

2023-01-15


1710. Missing template keyword in class-or-decltype

Section: 11.7  [class.derived]     Status: C++17     Submitter: Richard Smith     Date: 2013-07-03

[Adopted at the February/March, 2017 meeting.]

A class-or-decltype is used as a base-specifier and as a mem-initializer-id that names a base class. It is specified in 11.7 [class.derived] paragraph 1 as:

Consequently, a declaration like

  template<typename T> struct D : T::template B<int>::template C<int> {};

is ill-formed, although most implementations accept it; some actually require the use of the template keyword, although the relevant wording in 13.3 [temp.names] paragraph 4 only requires it in a qualified-id, not in a class-or-decltype. It would probably be good to add a production like

to the definition of class-or-decltype and explicitly mention those contexts in 13.3 [temp.names] as not requiring use of the template keyword.

Additional note (January, 2014):

This is effectively issues 314 and 343.

See also issue 1812.

Proposed resolution (February, 2014) [SUPERSEDED]:

  1. Change Clause 11 [class] paragraph 3 as follows:

  2. If a class is marked with the class-virt-specifier final and it appears as a base-type-specifier class-or-decltype in a base-clause (11.7 [class.derived]), the program is ill-formed. Whenever a class-key is followed...
  3. Change the grammar in 11.7 [class.derived] paragraph 1 as follows:

  4. Delete paragraph 4 and change paragraph 5 of 13.3 [temp.names] as follows, splitting paragraph 5 into two paragraphs and moving the example from paragraph 4 into paragraph 5:

  5. When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (13.8.3.2 [temp.dep.type]), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template. [Example: ... —end example]

    A name prefixed by the keyword template shall be a template-id or the name shall refer to a class template or alias template. [Note: The keyword template may not be applied to non-template members of class templates. —end note] The nested-name-specifier (_N4567_.5.1.1 [expr.prim.general]) of

    or a nested-name-specifier directly contained in such a nested-name-specifier (recursively), shall not be of the form

    [Note: That is, a simple-template-id shall not be prefixed by the keyword template in these cases. —end note]

    The keyword template is optional in a typename-specifier (13.8 [temp.res]), elaborated-type-specifier (9.2.9.4 [dcl.type.elab]), using-declaration (9.9 [namespace.udecl]), or class-or-decltype (11.7 [class.derived]), and in recursively directly-contained nested-name-specifiers thereof. In these contexts, a < token is always assumed to introduce a template-argument-list. [Note: Thus, if the preceding name is not a template-name, the program is ill-formed. —end note] In other contexts, when the name of a member template specialization appears after a nested-name-specifier that denotes a dependent type, but the name is not a member of the current instantiation, the member template name shall be prefixed by the keyword template. Similarly, when the name of a member template specialization appears after . or -> in a postfix-expression (7.6.1 [expr.post]) and the object expression of the postfix-expression is type-dependent, but the name is not a member of the current instantiation (13.8.3.2 [temp.dep.type]), the member template name shall be prefixed by the keyword template. Otherwise, the name is assumed to name a non-template. [Example:

        <From original paragraph 4>
    

    end example] [Note: As is the case with the typename prefix...

This resolution also resolves issues 314, 343, 1794, and 1812.

Additional note, November, 2014:

Concerns have been expressed over the clarity and organization of the proposed resolution, so the issue has been moved back to "review" status to allow CWG to address these concerns.

Proposed resolution, March, 2017:

  1. Change Clause 11 [class] paragraph 3 as follows:

  2. If a class is marked with the class-virt-specifier final and it appears as a base-type-specifier class-or-decltype in a base-clause ( 11.7 [class.derived]), the program is ill-formed. Whenever a class-key is followed by a class-head-name...
  3. Change the grammar in 11.7 [class.derived] paragraph 1 as follows:

  4. Change 11.7 [class.derived] paragraph 2 as followx:

  5. The type denoted by a base-type-specifier A class-or-decltype shall be denote a class type that is not an incompletely defined class (Clause 11 [class]); this. The class denoted by the class-or-decltype of a base-specifier is called a direct base class for the class being defined. During the lookup for a base class name...
  6. Change 13.3 [temp.names] paragraphs 4 and 5 as follows:

  7. When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation The keyword template is said to appear at the top level in a qualified-id if it appears outside of a template-argument-list or decltype-specifier. In a qualified-id of a declarator-id or in a qualified-id formed by a class-head-name ( Clause 11 [class]) or enum-head-name (9.7.1 [dcl.enum]), the keyword template shall not appear at the top level. In a qualified-id used as the name in a typename-specifier (13.8 [temp.res]), elaborated-type-specifier (9.2.9.4 [dcl.type.elab]), using-declaration (9.9 [namespace.udecl]), or class-or-decltype ( 11.7 [class.derived]), an optional keyword template appearing at the top level is ignored. In these contexts, a < token is always assumed to introduce a template-argument-list. In all other contexts, when naming a template specialization of a member of an unknown specialization (13.8.3.2 [temp.dep.type]), the member template name must shall be prefixed by the keyword template. Otherwise the name is assumed to name a non-template. [Example:...

    A name prefixed by the keyword template shall be a template-id or the name shall refer to a class template or an alias template. [Note: The keyword template may not be applied to non-template members of class templates. —end note]...

  8. Change 13.8 [temp.res] paragraph 5 as follows:

  9. A qualified name used as the name in a mem-initializer-id, a base-specifier, class-or-decltype ( 11.7 [class.derived]) or an elaborated-type-specifier is implicitly assumed to name a type, without the use of the typename keyword. In a nested-name-specifier that immediately contains a nested-name-specifier that depends on a template parameter, the identifier or simple-template-id is implicitly assumed to name a type, without the use of the typename keyword. [Note: The typename keyword is not permitted by the syntax of these constructs. —end note]