lrleon
lrleon

Reputation: 2648

Ambiguity between base and derived constructors

I have designed the following code snippet that shows my problem (the original one is more complicated):

#include <string>

struct A
{
  A(int, int) {}

  A(int p1 = 0, std::string p2 = "", int p3 = 0) {} // string for breaking ambiguity with previous ctor

  // There are a lot more of constructors for A class 
};

struct B : public A
{
  using A::A; // I want to inherit many base constructors in order to save work

  // But I need this particular constructor and it should override the
  // equivalent base constructor
  B(int p1 = 0, std::string p2 = "", int p3 = 0) {}
};

int main(int argc, char *argv[])
{
  B b(1); // gives "error: call to constructor of 'B' is ambiguous", what
      // of course is true, but I would want to inherit the other
      // base constructors. If I comment using A::A ==> this line compiles

  B b2(2, 3); // But if I comment using A::A ==> this line does not compile
}

So, my question: is there any way to break this ambiguity without hiding the lots of other constructors having the base class?

Thanks in advance

Upvotes: 3

Views: 585

Answers (2)

T.C.
T.C.

Reputation: 137301

The current inheriting constructors specification is...sort of messed up. Inheriting the A(int p1 = 0, std::string p2 = "", int p3 = 0) constructor implicitly declares three signatures: B(int), B(int, std::string), B(int, std::string, int), only the last of which is suppressed because of B's constructor declaration.

N4429, a proposal to fix numerous problems with the current specification, passed design review at the last committee meeting, and, if adopted, would fix your problem.

A workaround is to write a set of delegating constructors in B rather than use default arguments:

  B() : B(0) {}
  B(int p1) : B(p1, "") {}
  B(int p1, std::string p2) : B(p1, std::move(p2), 0) {}
  B(int p1, std::string p2, int p3) {}

This suppresses all three signatures that would have been declared from inheriting that base class constructor.

Upvotes: 6

Steephen
Steephen

Reputation: 15824

If you define derived class constructor, you should call base class constructor in initialization list as follows:

struct B : public A
{
 // using A::A; // I want to inherit many base constructors in order to save work

  // But I need this particular constructor and it should override the
  // equivalent base constructor
  B(int p1 = 0, int p2 = 0, int p3 = 0):A(p1,p2,p3) {}
};

Please note, you don't need to use using statement to resolve ambiguity in your derived class as using A::A;. When you derive publicly you will get all public and protected components of base class will be available in derived class.

DEMO: http://coliru.stacked-crooked.com/a/52451127e54c8591

Upvotes: 2

Related Questions