Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why "an inherited constructor is not a candidate for initialization from an expression of the same or derived type"?

I expected this to work

struct Parent
{
    Parent ();

    Parent (const Parent &);
};

struct Child : public Parent
{
    using Parent::Parent;
};

Parent p;

Child c (p);

Child inherits all of Parent's constructors, right?

Including Parent::Parent(const Parent &)?

x.cpp:15:11: error: no matching function for call to ‘Child::Child(Parent&)’
 Child c (p);
           ^
x.cpp:5:2: note: candidate: Parent::Parent(const Parent&)
  Parent (const Parent &);
  ^~~~~~
x.cpp:10:16: note:   inherited here
  using Parent::Parent;
                ^~~~~~
x.cpp:10:16: note:   an inherited constructor is not a candidate for initialization from an expression of the same or derived type
x.cpp:8:8: note: candidate: Child::Child()
 struct Child : public Parent
        ^~~~~

Why can't I construct a Child from a Parent?

like image 802
spraff Avatar asked Sep 13 '19 14:09

spraff


2 Answers

This is essentially CWG issue 2356: Base class copy and move constructors should not be inherited.

[over.match.funcs]/p9 now says:

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.

like image 69
cmeerw Avatar answered Oct 04 '22 13:10

cmeerw


Inheriting a constructor doesn't prevent the default copy constructor of Child from being generated by the compiler.

This implies that you have a Child::Child(const Child&) which is hiding the inherited constructor that can't be chosen by lookup resolution, as cppreference.com explains:

if an inherited constructor matches the signature of one of the constructors of Derived, it is hidden from lookup by the version found in Derived. If one of the inherited constructors of Base happens to have the signature that matches a copy/move constructor of the Derived, it does not prevent implicit generation of Derived copy/move constructor (which then hides the inherited version, similar to using operator=).

In §12.9 of C++11 ISO standard is it stated:

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 class where the using-declaration appears.

like image 32
Jack Avatar answered Oct 04 '22 15:10

Jack