简体   繁体   中英

Virtual Inheritance with Constructor Inheritance

I have a class hierarchy which boils down to

class Module { };

struct Port {
    Module& owner;
    Port(Module& owner) : owner(owner) {}
};

struct InPort    : virtual Port    { using Port::Port; };
struct OutPort   : virtual Port    { using Port::Port; };
struct InOutPort : InPort, OutPort { using Port::Port; };

As you can see, I would prefer to create some base functionality, and inherit it in a classic diamond pattern. I also would like to use constructor inheritance to make it as future proof as possible...

However, this does not work as written down above

prog.cpp: In function 'int main()':
prog.cpp:14:15: error: use of deleted function 'InOutPort::InOutPort(Module&)'
  InOutPort p(m);

Even replacing the definition of InOutPort with a more explicit version is not enough :

struct InOutPort : InPort, OutPort { InOutPort(Module& m) : Port(m), InPort(m), OutPort(m) { } };

Instead I seem to have to write down everything explicitly for it to work: :

struct InPort    : virtual Port    { InPort(Module& m) : Port(m) { } };
struct OutPort   : virtual Port    { OutPort(Module& m) : Port(m) { } };
struct InOutPort : InPort, OutPort { InOutPort(Module& m) : Port(m), InPort(m), OutPort(m) { } };

Is there a way to combine constuctor inheritance with virtual inheritance that I am overlooking?
If not, what alternative would you use?
Maybe variadic template constructors that perfectly forwards its arguments to all bases?

It doesn't appear that there is any way to do such a thing. In 12.9/8:

...An implicitly-defined inheriting constructor performs the set of initializations of the class that would be performed by a user-written inline constructor for that class with a mem-initializer-list whose only mem-initializer has a mem-initializer-id that names the base class denoted in the nested-name-specifier of the using-declaration and an expression-list as specified below...

In other words, the class whose constructor you inherit is the only base class that gets arguments forwarded to it. All other base classes need to have default constructors. Since you hid those default constructors in the intermediate classes by inheriting the parent constructor, you can't call them once you explicitly inherit the parent constructor.

I think you should be able to use inherited constructors for both intermediate classes and only write the explicit version for the most derived class [I didn't see that you already tried this - it does seem like a compiler bug from my understanding of the standard]. I'll update if I think of another better approach.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM