Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement a move constructor for a diamond-shaped inheritance?

I have a diamond-shaped hierarchy of classes, where there is no default constructor, nor copy constructors. The two constructors I have are a "move" one and another that takes a lvalue reference to an object:

struct base {
    base(base&&) = default;
    base(member_type&& m): member_(std::move(m)) {}
    member_type member_;
};

struct virt_1: virtual base {
    virt_1(virt_1&& rhs): base(std::move(rhs)) {}
    virt_1(member_type&& m): base(std::move(m)) {}
};

struct virt_2: virtual base {
    virt_2(virt_2&& rhs): base(std::move(rhs)) {}
    virt_2(member_type&& m): base(std::move(m)) {}
};

struct concrete: virt_1, virt_2 {
    concrete(concrete&& rhs) // ???
};

Besides not using a diamond-shaped hierarchy, is it possible to implement the move constructor for the concrete class?

Thanks!

like image 707
piwi Avatar asked Jul 08 '13 11:07

piwi


1 Answers

What's wrong with asking the compiler to provide the implementation?

concrete(concrete&&) = default;

I'd define the virt_1 and virt_2 move constructors as defaulted too.

You could write it out if you really wanted to:

concrete(concrete&& rhs)
: base(std::move(rhs)), virt_1(std::move(rhs)), virt_2(std::move(rhs))
{ }

Or if you really like typing:

    concrete(concrete&& rhs)
    : base(static_cast<base&&>(rhs)),
      virt_1(static_cast<virt_1&&>(rhs)),
      virt_2(static_cast<virt_2&&>(rhs))
    { }

The initializers for the virt_1 and virt_2 bases are useless, because they only call the base constructor and as it's a virtual base they won't do that when concrete has called it, but due to your choices of constructors you can't default-construct them and are required to initialize them with an rvalue even though they'll do nothing with it.

like image 127
Jonathan Wakely Avatar answered Sep 21 '22 10:09

Jonathan Wakely