Search code examples
c++classdefaultc++20function-definition

An example of a well-formed class definition with a defaulted special member function that the compiler makes deleted


In the C++20 standard, [dcl.fct.def.default], Explicitly-defaulted functions:

2 The type T1 of an explicitly defaulted special member function F is allowed to differ from the type T2 it would have had if it were implicitly declared, as follows:

(2.1) — T1 and T2 may have differing ref-qualifiers;

(2.2) — T1 and T2 may have differing exception specifications; and

(2.3) — if T2 has a parameter of type const C&, the corresponding parameter of T1 may be of type C&.

If T1 differs from T2 in any other way, then:

(2.4) — if F is an assignment operator, and the return type of T1 differs from the return type of T2 or T1’s parameter type is not a reference, the program is ill-formed;

(2.5) — otherwise, if F is explicitly defaulted on its first declaration, it is defined as deleted;

(2.6) — otherwise, the program is ill-formed

Could anybody provide an example of a special member function explicitly defaulted and that is deleted by the compiler. The function declaration should be well-formed.


Solution

  • The example from P0641, whence this wording:

    struct MyType {
      MyType(MyType&);  // no 'const'
    };
    
    template <typename T>
    struct Wrapper {
      Wrapper(const Wrapper&) = default;
      T t;
    };
    
    Wrapper<MyType> var;  // fails to instantiate
    

    Pretend there was actually a default constructor.

    This was previously ill-formed. Now, T1 (Wrapper's copy constructor) differs from it what it would have been were it implicitly declared (would have been Wrapper(Wrapper&) per [class.copy.ctor]/7). This doesn't match the cases in the first set of bullets (here T1 has const& but not T2, the bullet is in the opposite order), so we fall through to the second set of bullets - and we end up with Wrapper<MyType>'s copy constructor being deleted.


    A good example of where this would've come up in code is something like std::tuple (see LWG2086), where prior to these changes:

    struct A {
      A();
      A(A&);
    };
    std::tuple<A> x; // ill-formed
    

    Now, this is well-formed, just that tuple<A> isn't copyable.