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

309 views Asked by At
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.

2

There are 2 answers

0
Barry On BEST ANSWER

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).

1
n. m. could be an AI On

The passage you quote does not in fact prevent inheritance of copy constructors in C++14. Consider this instead:

B(B const&, int = 42) {}

This is a copy constructor, but it has two parameters. The passage only excludes a copy constructor with a single parameter. And when you supply both arguments, you can in fact initialize a D object with this constructor.

g++ error messages provide some insight.

note:   an inherited constructor is not a candidate for initialization from an expression of the same or derived type

Aha! A quick search in the draft standard finds this

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.