Title
Unclear boundaries of template declarations
Status
review
Section
13.1 [temp.pre]
Submitter
Jan Schultke

Created on 2024-02-21.00:00:00 last changed 7 hours ago

Messages

Date: 2024-12-15.00:00:00

Additional notes (December, 2024)

Subclause 7.5.5.3 [expr.prim.id.qual] paragraph 3 already interprets declarative nested-name-specifiers.

Possible resolution:

Change in 13.1 [temp.pre] paragraph 2 through 5 as follows:

The declaration in a template-declaration (if any) shall

  • declare or define a function, a class, or a variable, or
  • define a member function, a member class, a member enumeration, or a static data member of a class template or of a class nested within a class template, or
  • define a member template of a class or class template, or
  • be a friend-type-declaration, or
  • be a deduction-guide, or
  • be an alias-declaration.
The declaration shall not be an export-declaration or a simple-declaration whose decl-specifier-seq contains typedef.

A template-declaration is a declaration. If the declaration in a template-declaration introduces an entity using a declarative nested-name-specifier that nominates a primary class template or class template partial specialization C (7.5.5.3 [expr.prim.id.qual]), the template-declaration declares a member of C, and the nested-name-specifier is treated as a non-dependent reference to C for the purpose of further interpreting the declaration. Otherwise:

  • A class template is introduced by a template-declaration whose declaration is a simple-declaration that either contains a class-specifier in its decl-specifier-seq or consists solely of an elaborated-type-specifier.
  • A function template is introduced by a template-declaration whose declaration declares a function.
  • An alias template is introduced by a template-declaration whose declaration is an alias-declaration.
  • A variable template is introduced by a template-declaration whose declaration declares a variable.
[ Example:
  template<typename T> struct A {
    template<typename U> struct B;
    template<typename U> struct B<U*> {
      template<typename V> void f();
    };
  };
  template<typename T> // #1
  template<typename U> // #2
  template<typename V> // #3
  void A<T>::B<U*>::f() {}
The template-declaration #1 declares a member of the class template A, because A<T> is equivalent to the injected-class-name of A. The template-declaration #2 declares a member of the class template partial specialization A<T>::B<U*>, because A<T>::B<U*> is equivalent to the injected-class-name of the partial specialization when A<T> is treated as a non-dependent reference to the primary template A. The template-declaration #3 declares a function template that is a member of the class template partial specialization. -- end example ] A declaration introduced by a template declaration of a variable is a variable template. A variable template at class scope is a static data member template. [ Example: ... ]

[Note 2: A template-declaration can appear only as a namespace scope or class scope declaration. —end note] Its declaration shall not be an export-declaration. A template-declaration shall declare exactly one templated entity (not considering declarations inhabiting scopes nested therein). [ Example:

template <int>
struct S {} v;    // error: declares both a class template and a variable template
template <int>
struct V *v;      // OK, declares a variable template
-- end example ] In a function template declaration, the unqualified-id of the declarator-id shall be a name. [Note 3: A class or variable template declaration of a simple-template-id declares a partial specialization (13.7.6 [temp.spec.partial]). —end note]

In a template-declaration, explicit specialization, or explicit instantiation, the init-declarator-list in the declaration shall contain at most one declarator. [ Note: When such a declaration is used to declare a class template, no declarator is permitted, because the declarator would be considered to declare a variable or function template in addition to the class template. -- end note ]

Date: 2024-12-21.22:42:35

CWG 2024-06-26

This drafting lacks the required positional association of template-heads with the respective component of the nested-name-specifier.

Possible resolution (rebased on the current Working Draft) [SUPERSEDED]:

Change in 13.1 [temp.pre] paragraph 2 through 5 as follows:

The declaration in a template-declaration (if any) shall

  • declare or define a function, a class, or a variable, or
  • define a member function, a member class, a member enumeration, or a static data member of a class template or of a class nested within a class template, or
  • define a member template of a class or class template, or
  • be a friend-type-declaration, or
  • be a deduction-guide, or
  • be an alias-declaration.
The declaration shall not be an export-declaration or a simple-declaration whose decl-specifier-seq contains typedef.

A template-declaration is a declaration. If

  • the declaration in a template-declaration introduces an entity using a declarative nested-name-specifier (7.5.5.3 [expr.prim.id.qual]) that is dependent and equivalent to the injected-class-name of a class template or class template partial specialization C, and
  • the template-head of the template-declaration is equivalent to that of C,
the template-declaration declares a member of C, and the nested-name-specifier is treated as a non-dependent reference to C for the purpose of further interpreting the declaration. Otherwise:
  • A class template is introduced by a template-declaration whose declaration is a simple-declaration that either contains a class-specifier in its decl-specifier-seq or consists solely of an elaborated-type-specifier.
  • A function template is introduced by a template-declaration whose declaration declares a function.
  • An alias template is introduced by a template-declaration whose declaration is an alias-declaration.
  • A variable template is introduced by a template-declaration whose declaration declares a variable.
[ Example:
  template<typename T> struct A {
    template<typename U> struct B;
    template<typename U> struct B<U*> {
      template<typename V> void f();
    };
  };
  template<typename T> // #1
  template<typename U> // #2
  template<typename V> // #3
  void A<T>::B<U*>::f() {}
The template-declaration #1 declares a member of the class template A, because A<T> is equivalent to the injected-class-name of A. The template-declaration #2 declares a member of the class template partial specialization A<T>::B<U*>, because A<T>::B<U*> is equivalent to the injected-class-name of the partial specialization when A<T> is treated as a non-dependent reference to the primary template A. The template-declaration #3 declares a function template that is a member of the class template partial specialization. -- end example ] A declaration introduced by a template declaration of a variable is a variable template. A variable template at class scope is a static data member template. [ Example: ... ]

[Note 2: A template-declaration can appear only as a namespace scope or class scope declaration. —end note] Its declaration shall not be an export-declaration. A template-declaration shall declare exactly one templated entity (not considering declarations inhabiting scopes nested therein). [ Example:

template <int>
struct S {} v;    // error: declares both a class template and a variable template
template <int>
struct V *v;      // OK, declares a variable template
-- end example ] In a function template declaration, the unqualified-id of the declarator-id shall be a name. [Note 3: A class or variable template declaration of a simple-template-id declares a partial specialization (13.7.6 [temp.spec.partial]). —end note]

In a template-declaration, explicit specialization, or explicit instantiation, the init-declarator-list in the declaration shall contain at most one declarator. [ Note: When such a declaration is used to declare a class template, no declarator is permitted, because the declarator would be considered to declare a variable or function template in addition to the class template. -- end note ]

Date: 2024-12-17.11:14:03

Proposed resolution (approved by CWG 2024-04-05) [SUPERSEDED]:

Change in 13.1 [temp.pre] paragraph 2 through 5 as follows:

The declaration in a template-declaration (if any) shall

  • declare or define a function, a class, or a variable, or
  • define a member function, a member class, a member enumeration, or a static data member of a class template or of a class nested within a class template, or
  • define a member template of a class or class template, or
  • be a deduction-guide, or
  • be an alias-declaration.
The declaration shall not be an export-declaration or a simple-declaration whose decl-specifier-seq contains typedef.

A template-declaration is a declaration. If

  • the declaration in a template-declaration introduces an entity using a declarative nested-name-specifier (7.5.5.3 [expr.prim.id.qual]) that is dependent and equivalent to the injected-class-name of a class template or class template partial specialization C, and
  • the template-head of the template-declaration is equivalent to that of C,
the template-declaration declares a member of C, and the nested-name-specifier is treated as a non-dependent reference to C for the purpose of further interpreting the declaration. Otherwise:
  • A class template is introduced by a template-declaration whose declaration is a simple-declaration that either contains a class-specifier in its decl-specifier-seq or consists solely of an elaborated-type-specifier.
  • A function template is introduced by a template-declaration whose declaration declares a function.
  • An alias template is introduced by a template-declaration whose declaration is an alias-declaration.
  • A variable template is introduced by a template-declaration whose declaration declares a variable.
[ Example:
  template<typename T> struct A {
    template<typename U> struct B;
    template<typename U> struct B<U*> {
      template<typename V> void f();
    };
  };
  template<typename T> // #1
  template<typename U> // #2
  template<typename V> // #3
  void A<T>::B<U*>::f() {}
The template-declaration #1 declares a member of the class template A, because A<T> is equivalent to the injected-class-name of A. The template-declaration #2 declares a member of the class template partial specialization A<T>::B<U*>, because A<T>::B<U*> is equivalent to the injected-class-name of the partial specialization when A<T> is treated as a non-dependent reference to the primary template A. The template-declaration #3 declares a function template that is a member of the class template partial specialization. -- end example ] A declaration introduced by a template declaration of a variable is a variable template. A variable template at class scope is a static data member template. [ Example: ... ]

[Note 2: A template-declaration can appear only as a namespace scope or class scope declaration. —end note] Its declaration shall not be an export-declaration. A template-declaration shall declare exactly one template or member of a template. [ Example:

template <int>
struct S {} v;    // error: declares both a class template and a variable template
template <int>
struct V *v;      // OK: declares a variable template
-- end example ] In a function template declaration, the unqualified-id of the declarator-id shall be a name. [Note 3: A class or variable template declaration of a simple-template-id declares a partial specialization (13.7.6 [temp.spec.partial]). —end note]

In a template-declaration, explicit specialization, or explicit instantiation, the init-declarator-list in the declaration shall contain at most one declarator. [ Note: When such a declaration is used to declare a class template, no declarator is permitted, because the declarator would be considered to declare a variable or function template in addition to the class template. -- end note ]

Date: 2024-04-05.21:08:10

(From submission #506.)

Consider:

  template <int>
  struct S {} v;

Is this a declaration of a class template or a declaration of a variable template, or neither? Implementations uniformly reject.

Another example:

  template<class T>
  typedef struct C F; 
History
Date User Action Args
2024-12-21 22:42:35adminsetmessages: + msg7932
2024-07-30 22:40:05adminsetstatus: drafting -> review
2024-06-26 19:00:47adminsetmessages: + msg7756
2024-06-26 19:00:47adminsetstatus: tentatively ready -> drafting
2024-04-05 21:08:10adminsetmessages: + msg7656
2024-04-05 21:08:10adminsetstatus: open -> tentatively ready
2024-02-21 00:00:00admincreate