Как неявно преобразовать возвращаемое значение в базовый класс, не вызывая конструктор копирования? - PullRequest
0 голосов
/ 18 ноября 2018

Рассмотрим два класса, таких как эти:

#include <cstdio>

using std::puts;

class Base {
public:
    Base() { puts("Create base"); }
    Base(const Base &) { puts("Copy base"); }
    Base(Base &&) { puts("Move base"); }
    virtual ~Base() { puts("Delete base"); }
    Base & operator=(const Base &) = delete;
};

class Derived : public Base {
public:
    Derived() { puts("Create derived"); }
    Derived(const Derived &) { puts("Copy derived"); }
    Derived(const Base &) { puts("Copy derived from base"); }
    Derived(Derived &&) { puts("Move derived"); }
    Derived(Base &&) { puts("Move derived from base"); }
    virtual ~Derived() { puts("Delete derived"); }
    Derived & operator=(const Derived &) = delete;
};

и функция:

Base fn() {
    Derived d;
    // Fill in d here
    return d;
}

Копирование базового класса является очень дорогой операцией, однако, поскольку производный класс не сильно отличается, он может быть преобразован в базовый объект с использованием семантики перемещения. Однако я не могу заставить компилятор использовать это неявно вместо конструкции копирования. Я попытался добавить следующее безуспешно:

Base::Base(Derived &&);
Derived::operator Base &&() &&;
Derived::operator Base() &&;

Есть ли способ избежать конструктора копирования, изменив только два класса, а не функцию fn?

РЕДАКТИРОВАТЬ: Я знаю, как это сделать, если я мог бы изменить функцию fn, но я не могу.

1 Ответ

0 голосов
/ 18 ноября 2018

Base::Base(Derived &&); будет работать нормально, если добавлено правильно.

#include <utility>

class Derived;
class Base {
  // ...
  Base(Derived &&);
};

// Derived here

Base::Base(Derived &&d) : Base(std::forward<Base>(d)) {}

Единственная сложная часть - std::forward<Base>(d).Но в конечном итоге это просто приведение, где мы просим перенаправить d как Base xvalue.Тогда делегированный конструктор перемещения делает правильные вещи.

Смотрите его вживую

RVO гарантированно попытается вернуть локальную переменную, как если бы онабыл первым значением.Поскольку теперь существует соответствующий ему конструктор, он будет работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...