Search code examples
c++inheritanceconstructormove-semantics

Deleted move constructor in base class does not stop derived class object to be returned from a function


Given base class A and derived class B, A has deleted move constructor:

class A {
public: 
  A()  {}
  A(const A&) = default;
  A(A&&) = delete; 
};

class B : public A
{ 
};

In such case, the following function does not compile because of deleted move constructor:

A f() {
  A a;
  return a;
}

but the similar function for B does not report any error:

B g() {
  B b;
  return b;
}

Does it mean that move constructor in B is not deleted? I want to know what is the rule in the standard.


Solution

  • The move constructor in B is deleted, but does not participate in overload resolution. According to cppreference:

    The implicitly-declared or defaulted move constructor for class T is defined as deleted if any of the following is true:

    • T has non-static data members that cannot be moved (have deleted, inaccessible, or ambiguous move constructors);
    • T has direct or virtual base class that cannot be moved (has deleted, inaccessible, or ambiguous move constructors);
    • T has direct or virtual base class or a non-static data member with a deleted or inaccessible destructor;
    • T is a union-like class and has a variant member with non-trivial move constructor.

    A defaulted move constructor that is deleted is ignored by overload resolution (otherwise it would prevent copy-initialization from rvalue).

    The second bullet point applies: B has a direct base class, A, with a deleted move constructor. So B's implicitly-declared move constructor is defined as deleted.

    However, when the return statement is evaluating which constructor of B to use, the deleted move constructor is not considered but the valid copy constructor is.