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

2024-12-19


2478. Properties of explicit specializations of implicitly-instantiated class templates

Section: 13.9.4  [temp.expl.spec]     Status: C++23     Submitter: Mark Hall     Date: 2021-02-02

[Accepted as a DR at the February, 2023 meeting.]

According to 13.9.4 [temp.expl.spec] paragraph 16,

A member or a member template of a class template may be explicitly specialized for a given implicit instantiation of the class template, even if the member or member template is defined in the class template definition. An explicit specialization of a member or member template is specified using the syntax for explicit specialization.

The relationship between this construct and paragraph 14 is not clear:

Whether an explicit specialization of a function or variable template is inline, constexpr, or an immediate function is determined by the explicit specialization and is independent of those properties of the template.

(See also 9.2.6 [dcl.constexpr] paragraph 1, note 1.) Is this intended to apply to explicit specializations of members of implicitly-instantiated class templates? For example:

  template<typename T> struct S {
    int f();
    constexpr int g();
  };
  template<> constexpr int S<int>::f() {  // OK, constexpr?
    return 0;
  }
  template<> int S<int>::g() {            // OK, not constexpr?
    return 0;
  }

There is implementation divergence on the treatment of this example. This divergence may relate to interpretation of the requirement in 9.2.6 [dcl.constexpr] paragraph 1,

If any declaration of a function or function template has a constexpr or consteval specifier, then all its declarations shall contain the same specifier.

Is an explicit specialization of a member of an implicitly-instantiated class template a declaration of that member? A similar question also applies to the constinit specifier as specified in 9.2.7 [dcl.constinit] paragraph 1:

If the specifier is applied to any declaration of a variable, it shall be applied to the initializing declaration.

(Note that constinit is not mentioned in 13.9.4 [temp.expl.spec] paragraph 14.) For example:

  template<typename T> struct S {
    static constinit T x;
  };
  template<> int S<int>::x = 10;    // constinit required?
  extern char c;
  template<> short S<char>::x = c;  // error, c not constant?

(Possibly relevant is the fact that default arguments are prohibited in explicit specializations of member functions of implicitly-instantiated class templates, per 13.9.4 [temp.expl.spec] bullet 21.3.)

CWG 2022-11-10

A specialization of a member of a class template redeclares the member of the primary template and thus the redeclaration rules apply. In passing, it was noticed that the rule governing explicit specializations in general omitted treatment of constinit, which was considered an oversight.

Proposed resolution (approved 2023-02-09):

Change in 13.9.4 [temp.expl.spec] paragraph 13 as follows:

Whether an explicit specialization of a function or variable template is inline, constexpr, constinit, or consteval an immediate function is determined by the explicit specialization and is independent of those properties of the template.