c++overloadingc++14inheriting-constructors

Inheriting constructor and providing new overload: no arguments base constructor seems to not participate in overload resolution


Tests show a strange behavior (c++14, g++ 4.9.1, clang 3.5.5):

To sum it up:


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


Solution

  • 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){}
    };
    

    (live demo)

    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.