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


1135. Explicitly-defaulted non-public special member functions

Section: 9.5.2  [dcl.fct.def.default]     Status: C++11     Submitter: FI     Date: 2010-08-02

[Voted into the WP at the March, 2011 meeting.]

N3092 comment FI 1

It should be allowed to explicitly default a non-public special member function on its first declaration. It is very likely that users will want to default protected/private constructors and copy constructors without having to write such defaulting outside the class.

Proposed resolution (November, 2010):

  1. Change 9.5.2 [dcl.fct.def.default] paragraphs 1-5 as follows:

  2. A function definition of the form:

    is called an explicitly-defaulted definition. A function that is explicitly defaulted shall

    [Note: This implies that parameter types, return type, and cv-qualifiers must match the hypothetical implicit declaration. —end note]

    An explicitly-defaulted function may be declared constexpr only if it would have been implicitly declared as constexpr, and may have an explicit exception-specification only if it is compatible (14.5 [except.spec]) with the exception-specification on the implicit declaration. If it a function is explicitly defaulted on its first declaration,

    [Note: Such a special member function may be trivial, and thus its accessibility and explicitness should match the hypothetical implicit definition; see below. —end note] [Example:

      struct S {
        constexpr S() = default;                 //ill-formed: implicit S() is not constexpr
        S(int a = 0) = default;                  // ill-formed: default argument
        void operator=(const S&) = default;      // ill-formed: non-matching return type
        ~S() throw(int) = default;               // ill-formed: exception specification doesn't match
      private:
        int i;
        S(S&);                                   // OK: private copy constructor
      };
      S::S(S&) = default;                        // OK: defines copy constructor
    

    end example]

    Explicitly-defaulted functions and implicitly-declared functions are collectively called defaulted functions, and the implementation shall provide implicit definitions for them (11.4.5 [class.ctor] 11.4.7 [class.dtor], 11.4.5.3 [class.copy.ctor]), which might mean defining them as deleted. A special member function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration. A user-provided explicitly-defaulted function (i.e., explicitly defaulted after its first declaration) is defined at the point where it is explicitly defaulted; if such a function is implicitly defined as deleted, the program is ill-formed. [Note: while an implicitly-declared special member function is inline (11.4.4 [special]), an explicitly-defaulted definition may be non-inline. Non-inline definitions are user-provided, and hence non-trivial (11.4.5 [class.ctor], 11.4.7 [class.dtor], 11.4.5.3 [class.copy.ctor]). This rule enables Declaring a function as defaulted after its first declaration can provide efficient execution and concise definition while enabling a stable binary interface to an evolving code base. —end note]

    [Example:

      struct trivial {
        trivial() = default;
        trivial(const trivial&) = default;
        trivial(trivial&&) = default;
        trivial& operator=(const trivial&) = default;
        trivial& operator=(trivial&&) = default;
        ~trivial() = default;
      };
    
      struct nontrivial1 {
        nontrivial1();
      };
    
      nontrivial1::nontrivial1() = default;           // not inline first declaration
    
      struct nontrivial2 {
        nontrivial2();
      };
      inline nontrivial2::nontrivial2() = default;    // not first declaration
    
      struct nontrivial3 {
        virtual ~nontrivial3() = 0;                   // virtual
      };
      inline nontrivial3::~nontrivial3() = default;   // not first declaration
    

    end example]

  3. Change 11.4.5 [class.ctor] paragraph 5 as follows:

  4. ...A default constructor is trivial if it is neither not user-provided nor deleted and...
  5. Change 11.4.7 [class.dtor] paragraph 3 as follows:

  6. ...A destructor is trivial if it is neither not user-provided nor deleted and...
  7. Change 11.4.5.3 [class.copy.ctor] paragraph 13 as follows:

  8. A copy/move constructor for class X is trivial if it is neither not user-provided nor deleted and...
  9. Change 11.4.5.3 [class.copy.ctor] paragraph 27 as follows:

  10. A copy/move assignment operator for class X is trivial trivial if it is neither not user-provided nor deleted and...

This resolution also resolves issues 1136, 1137, 1140, 1145, 1149, and 1208.