如何在不调用复制构造函数的情况下将返回值隐式转换为基类?

时间:2018-11-18 10:18:02

标签: c++ c++11

请考虑以下两个类:

#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 :(得分:1)

如果正确添加,

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转发。然后委派的move构造函数执行正确的操作。

See it live

保证RVO尝试返回本地变量,就好像它首先是右值一样。由于现在有一个与之匹配的构造函数,它将可以正常工作。