Inheriting constructors
- using-declaration that names a constructor implicitly declares a set of inheriting constructors. The candidate set of inherited constructors from the class X named in the using-declaration consists of actual constructors and notional constructors that result from the transformation of defaulted parameters as follows:
- all non-template constructors of X, and
- for each non-template constructor of X that has at least one parameter with a default argument, the set of constructors that results from omitting any ellipsis parameter specification and successively omitting parameters with a default argument from the end of the parameter-type-list, and
- all constructor templates of X, and
- for each constructor template of X that has at least one parameter with a default argument, the set of constructor templates that results from omitting any ellipsis parameter specification and successively omitting parameters with a default argument from the end of the parameter-type-list.
- all non-template constructors of X, and
- 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.
- Similarly, for each constructor template in the candidate set of inherited constructors, a constructor template is implicitly declared with the same constructor characteristics unless there is an equivalent user-declared constructor template in the complete class where the using-declaration appears.
- Note: Default arguments are not inherited.
- A constructor so declared has the same access as the corresponding constructor in X. It is deleted if the corresponding constructor in X is deleted
- Examples:
struct B1 {
B1(int);
};
struct B2 {
B2(int = 13, int = 42);
};
struct D1 : B1 {
using B1::B1; // using-declaration
};
struct D2 : B2 {
using B2::B2;
};
The candidate set of inherited constructors in D1 for B1 is
— B1(const B1&)
— B1(B1&&)
— B1(int)
The set of constructors present in D1 is
— D1(), implicitly-declared default constructor, ill-formed if odr-used
— D1(const D1&), implicitly-declared copy constructor, not inherited
— D1(D1&&), implicitly-declared move constructor, not inherited
— D1(int), implicitly-declared inheriting constructor
The candidate set of inherited constructors in D2 for B2 is
— B2(const B2&)
— B2(B2&&)
— B2(int = 13, int = 42)
— B2(int = 13)
— B2()
The set of constructors present in D2 is
— D2(), implicitly-declared default constructor, not inherited
— D2(const D2&), implicitly-declared copy constructor, not inherited
— D2(D2&&), implicitly-declared move constructor, not inherited
— D2(int, int), implicitly-declared inheriting constructor
— D2(int), implicitly-declared inheriting constructor
struct B1 {
B1(int);
};
struct B2 {
B2(int);
};
struct D1 : B1, B2 {
using B1::B1;
using B2::B2;
}; // ill-formed: attempts to declare D1(int) twice
struct D2 : B1, B2 {
using B1::B1;
using B2::B2;
D2(int); // OK: user declaration supersedes both implicit declarations
};
template< class T >
struct D : T {
using T::T; // declares all constructors from class T
~D() { std::clog << "Destroying wrapper" << std::endl; }
};