lundi 18 janvier 2021

Can I make a base class move constructor overload preferable to a derived class copy constructor?

I have two classes (call them base and derived) that have an uncommon set of semantics:

  • base is the parent of derived, as you may expect
  • base is copyable and movable
  • derived is movable but not copyable
  • base is not copy-constructible from derived

This is all pretty straightforward. I would like, though, for base to be move-constructible from derived, so I could do something like:

derived d;
base b(std::move(d));

My attempt at expressing this is as follows:

#include <utility>

struct derived;

struct base
{
    base() { }
    base(const derived &) = delete;
    base(const base &) { }
    base(base &&) { }
};

struct derived : base 
{ 
    derived() { }
    derived(const derived &) = delete;
    derived(derived &&) = default;
};

base func()
{
    derived d;
    return std::move(d);
}

int main()
{
    func();
}

(I know in a real example I should include the assignment operators too, those are elided for brevity)

However, the above fails to compile:

<source>: In function 'base func()':
<source>:23:23: error: use of deleted function 'base::base(const derived&)'
   23 |     return std::move(d);
      |                       ^
<source>:8:5: note: declared here
    8 |     base(const derived &) = delete;
      |     ^~~~
ASM generation compiler returned: 1
<source>: In function 'base func()':
<source>:23:23: error: use of deleted function 'base::base(const derived&)'
   23 |     return std::move(d);
      |                       ^
<source>:8:5: note: declared here
    8 |     base(const derived &) = delete;
      |     ^~~~

The compiler is preferring base's deleted constructor from const derived &. My intent was that the expression std::move(d), of type derived &&, would invoke base's move constructor instead.

Is there a way to make this happen?

Aucun commentaire:

Enregistrer un commentaire