c++constructormultiple-inheritancevirtual-inheritanceinherited-constructors

Constructor arguments for virtual base classes


Consider the following code:

class A {
  int i;
public:
  A(int index) : i(index) {}
  int get() { return i; }
};

class B : virtual public A {
public:
  using A::A;
};

class C : virtual public A {
public:
  using A::A;
};

class D : public B, public C {
public:
  D(int i) : A(i), B(i), C(i) {}
};

int main() {
  D d(1);
  return 0;
}

While clang 3.7 accepts the above, gcc 4.8 with -std=c++11 complains about this code:

 In constructor 'D::D(int)':
20:29: error: use of deleted function 'B::B(int)'
   D(int i) : A(i), B(i), C(i) {}
                             ^
10:12: note: 'B::B(int)' is implicitly deleted because the default definition would be ill-formed:
   using A::A;
            ^
10:12: error: no matching function for call to 'A::A()'
10:12: note: candidates are:
4:3: note: A::A(int)
   A(int index) : i(index) {}
   ^
4:3: note:   candidate expects 1 argument, 0 provided
1:7: note: constexpr A::A(const A&)
 class A {
       ^
1:7: note:   candidate expects 1 argument, 0 provided
1:7: note: constexpr A::A(A&&)
1:7: note:   candidate expects 1 argument, 0 provided
20:29: error: use of deleted function 'C::C(int)'
   D(int i) : A(i), B(i), C(i) {}
                             ^
15:12: note: 'C::C(int)' is implicitly deleted because the default definition would be ill-formed:
   using A::A;
            ^
15:12: error: no matching function for call to 'A::A()'
15:12: note: candidates are:
4:3: note: A::A(int)
   A(int index) : i(index) {}
   ^
4:3: note:   candidate expects 1 argument, 0 provided
1:7: note: constexpr A::A(const A&)
 class A {
       ^
1:7: note:   candidate expects 1 argument, 0 provided
1:7: note: constexpr A::A(A&&)
1:7: note:   candidate expects 1 argument, 0 provided

Is the code I wrote valid according to the standard? Is it the best way to achieve what I'm trying, i.e. passing a constructor argument down a multi-inheritance tree to the common base class which actually holds the data? Or can I somehow simplify this or make it work with gcc as well? Am I right to assume that a class which inherits a virtual base class indirectly via multiple parents will always have to explicitely call the constructor of the base directly?


Solution

  • This is GCC bug 58751. Your code should compile as it does in Clang. GCC has had problems with inheriting constructors with virtual inheritance in the past.

    A workaround would be to manually write the forwarding constructor.

    class B : virtual public A {
    public:
      B(int i) : A(i) {}
    };
    
    class C : virtual public A {
    public:
      C(int i) : A(i) {}
    };