Title
Explicit specializations of deleted member functions
Status
cd5
Section
13.9.4 [temp.expl.spec]
Submitter
Richard Smith

Created on 2016-04-17.00:00:00 last changed 40 months ago

Messages

Date: 2017-11-15.00:00:00

Proposed resolution (November, 2017)

Change 13.9.2 [temp.inst] paragraph 2, breaking the running text into bullets, as follows:

The implicit instantiation of a class template specialization causes

  • the implicit instantiation of the declarations, but not of the definitions, default arguments, or noexcept-specifiers of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friends; and

  • it causes the implicit instantiation of the definitions of deleted member functions, unscoped member enumerations, and member anonymous unions.

The implicit instantiation of a class template specialization does not cause the implicit instantiation of default arguments or noexcept-specifiers of the class member functions. [Example:

  template<class T>
  struct C {
    void f() { T x; }
    void g() = delete;
  };
  C<void> c;                       // OK, definition of C<void>::f is not instantiated at this point
  template<> void C<int>::g() { }  // error: redefinition of C<int>::g

end example] However, for the purpose of determining whether an instantiated redeclaration is valid according to 6.3 [basic.def.odr] and 11.4 [class.mem], a declaration that corresponds to a definition in the template is considered to be a definition. [Example:

Date: 2016-12-15.00:00:00

Notes from the December, 2016 teleconference:

=delete definitions of member functions should be instantiated when instantiating a class template. That would make the example an ill-formed redefinition.

Date: 2018-03-15.00:00:00

[Accepted as a DR at the March, 2018 (Jacksonville) meeting.]

Although the Standard allows for explicitly specializing a deleted function template, member function of a class template, or member function template with a non-deleted definition, this seems to be problematic for non-template member functions of class templates. For example:

  template<typename T> struct A {
    A(const A&) = delete;
    A(A&&) = default;
  };
  static_assert(is_trivially_copyable(A<int>));
  template<> struct A<int>::A(const A&) { /* ... */ }
  static_assert(is_trivially_copyable(A<int>));
  template<typename T> struct B {
    virtual void f() = delete;
  };
  struct C : B<int> { void f() override = delete; }; // ok, overriding deleted with deleted 
  template<> void B<int>::f() {} // would make C retroactively ill-formed? 
History
Date User Action Args
2020-12-15 00:00:00adminsetstatus: dr -> cd5
2018-04-11 00:00:00adminsetstatus: tentatively ready -> dr
2018-02-27 00:00:00adminsetmessages: + msg5872
2018-02-27 00:00:00adminsetstatus: open -> tentatively ready
2017-02-06 00:00:00adminsetmessages: + msg5844
2016-04-17 00:00:00admincreate