Search code examples
c++c++14c++17language-lawyerinherited-constructors

Can copy/move constructors be inherited by using-declaration in c++17?


struct B {
  B(int) {}
  B(B const&) {}
};

struct D: B {
  using B::B;
};

int main(void) {
  B b(5);
  D d(b); // error
  return 0;
}

c++14 explicitly excludes copy/move constructors from inherited constructors in 12.9 [class.inhctor]/p3.

For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class.

But I could not find any detailed descriptions in c++17. clang/gcc show that copy/move constructors of base class are not inherited. Can someone provide where it is explained in the standard? Thanks.


Solution

  • The new wording is in [over.match.funcs]/8:

    A constructor inherited from class type C ([class.inhctor.init]) that has a first parameter of type “reference to cv1 P” (including such a constructor instantiated from a template) is excluded from the set of candidate functions when constructing an object of type cv2 D if the argument list has exactly one argument and C is reference-related to P and P is reference-related to D. [ Example:

    struct A {
      A();                                  // #1
      A(A &&);                              // #2
      template<typename T> A(T &&);         // #3
    };
    
    struct B : A {
      using A::A;
      B(const B &);                         // #4
      B(B &&) = default;                    // #5, implicitly deleted
    
      struct X { X(X &&) = delete; } x;
    };
    
    extern B b1;
    B b2 = static_cast<B&&>(b1);            // calls #4: #1 is not viable, #2, #3, and #5 are not candidates
    struct C { operator B&&(); };
    B b3 = C();                             // calls #4
    

    end example ]

    In your example, B's inherited copy constructor is excluded from the set of candidates (that constructor has a first parameter of type reference to const B, the argument list has exactly one argument - b, and B and D are reference-related).