Tests show a strange behavior (c++14
, g++ 4.9.1
, clang 3.5.5
):
To sum it up:
B
provides no other constructors it can use A::A()
B
provides other constructors it cannot use A::A()
, but it uses A::A(whatever arguments)
, which is unexpected behavior (to me at least).Setup 1:
struct A {
A() {};
A(int) {}; // with or without this overload the result are the same
};
struct B : A {
using A::A;
};
B b0{}; // OK
Setup 2:
struct A {
A() {}; // with a default constructor instead (empty class A)
// the results are the same
};
struct B : A {
using A::A;
B(int){}
};
B b0{}; // no matching constructor
B b1{24}; // OK
Setup 3:
struct A {
A() {};
A(int) {};
};
struct B : A {
using A::A;
B(int, int){}
};
B b0{}; // no matching constructor
B b1{24}; // OK
B b2{24, 42}; // OK
Why is this happening and how can it be "fixed".
I can't tell you the rationale for this, but I can at least tell you that it is standard-mandated:
[C++11: 12.9/3]
: 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. [..]
Since the default B()
invokes the default A()
, you can "fix" it like this:
struct B : A
{
B() = default;
using A::A;
B(int, int){}
};
The following wording from the original proposal (n2540) suggests that this fix's ease and symmetry is more or less the driving factor behind the decision, though I still find that to be somewhat unsatisfactory. Oh well.
Copy and default constructors are not forwarded, deferring to the existing rules for implicitly declaring copy/default constructors.