从临时成员中取走成员时的复制/移动

luk*_*k32 6 c++ c++14 c++17

我想在没有不必要的移动或复制的情况下取出临时成员.

假设我有:

class TP {
    T _t1, _t2;
};
Run Code Online (Sandbox Code Playgroud)

我想得到_t1,_t2来自TP().没有复制/移动成员是否可能?

我尝试过使用元组并试图"转发"(我认为不可能)成员,但我能得到的最好的是一个动作,或者成员立即死亡.

在下面的操场中使用B::as_tuple2最终会员过早死亡,除非结果绑定到非ref类型,否则会移动成员.在客户端,B::as_tuple简单的移动是安全的auto.

我认为这应该在技术上是可行的,因为临时死亡,并且成员在他们可以绑定到调用站点上的变量时死亡(我错了吗?),并且类似结构的结构化绑定按预期工作.

是否可以将成员的生命延长/传递到外部变量,或者忽略移动/复制?我需要它与c ++ 14版本,但我无法让它在c ++ 17上工作,所以我对两者都感兴趣.

游乐场:

#include <tuple>
#include <iostream>

using std::cout;
class Shawty {
/**
 * Pronounced shouty.
 **/
    public:
    Shawty() : _id(Shawty::id++) {cout << _id << " ctor\n"; }
    Shawty(Shawty && s) : _id(Shawty::id++) { cout << _id << " moved from " << s._id << "\n"; }
    Shawty(const Shawty & s) : _id(Shawty::id++) { cout << _id << " copied from " << s._id << "\n"; }
    Shawty& operator=(Shawty && s) { cout << _id << " =moved from " << s._id << "\n"; return *this;}
    Shawty& operator=(Shawty & s) { cout << _id << " =copied from " << s._id << "\n"; return *this;}
    ~Shawty() {cout << _id << " dtor\n"; }
    int _id;
    static int id;
};
int Shawty::id = 0;

class B {
public:
    auto as_tuple() && {return std::make_tuple(std::move(_s1), std::move(_s2));}
    auto as_tuple2() && {return std::forward_as_tuple(std::move(_s1), std::move(_s2));}

private:
    Shawty _s1, _s2;
};

struct S {
    Shawty _s1, _s2;
};

int main() {
    std::cout << "----------\n";
    auto [s1, s2] = B().as_tuple2();
    std::cout << "---------\n";
    auto tpl1 = B().as_tuple2();
    std::cout << "----------\n";
    std::tuple<Shawty, Shawty> tpl2 = B().as_tuple2();
    std::cout << "----------\n";

    std::cout << std::get<0>(tpl1)._id << '\n';
    std::cout << std::get<1>(tpl1)._id << '\n';
    std::cout << std::get<0>(tpl2)._id << '\n';
    std::cout << std::get<1>(tpl2)._id << '\n';
    std::cout << s1._id << '\n';
    std::cout << s2._id << '\n';

    std::cout << "--struct--\n";
    auto [s3, s4] = S{};
    std::cout << s3._id << '\n';
    std::cout << s4._id << '\n';
    std::cout << "----------\n";

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

eer*_*ika 0

不可以。不可能将多个成员的生命周期延长到超出超级对象的生命周期。

因此,在不复制的情况下“获取”成员的唯一方法是保持超级对象处于活动状态,并引用它们:

// member function
auto as_tuple3() & {
    return std::make_tuple(std::ref(_s1), std::ref(_s2));
}

// usage
B b;
auto [s1, s2] = b.as_tuple3();
Run Code Online (Sandbox Code Playgroud)

通过将引用绑定到单个成员来延长对象生命周期的示例。请注意,这要求可以从绑定引用的位置访问该成员(不是您的示例中的情况,其中该成员是私有的):

auto&& s1 = B{}._s1;
Run Code Online (Sandbox Code Playgroud)