返回本地对象的元组

时间:2018-08-28 17:54:55

标签: c++ templates c++17 move-semantics structured-bindings

如何利用结构化绑定和元组返回函数本地的对象?

在一个函数中,我正在创建互相引用的局部对象,并且我想在元组中返回这些对象,并在每次调用该函数时使用结构化绑定来标识它们。我目前有这个:

std::tuple<Owner&&, State<Controller>&&, State<Ancillary>&&, State<Compressor>&&>
inline makeOwner() {
    State<Controller>&& controller = State<Controller>();
    State<Ancillary>&&  ancillary  = State<Ancillary>();
    State<Compressor>&& compressor = State<Compressor>();

    Owner&& owner = Owner(controller, ancillary, compressor);

    return {owner, controller, ancillary, compressor};
}

// using the function later

const &&[owner, controller, ancillary, compressor] = makeOwner();

这不起作用,并且我收到一条错误消息,指出返回值不可转换为上述返回类型的元组。我不确定为什么会这样,因为类型与声明匹配。

最终,我正在尝试创建一个便捷函数,因此不必在每次要创建新所有者时都在函数中键入四行。这是我尝试使用结构化绑定来简化此过程。

编辑: 我应该注意,我希望最后一行中的绑定引用所有者内部的对象。因此,副本不足。

2 个答案:

答案 0 :(得分:4)

  

我希望最后一行中的绑定引用所有者内部的对象。

让我们忽略所有新的语言功能,然后回到基础知识。您希望它如何工作?

int&& f() { return 0; }
int&& r = f();

您希望r是对f内部局部变量的引用吗?但这在f()执行结束时被销毁。该代码可以编译,但是r是一个悬空引用。

确保此安全的唯一方法是确保f()返回对绝对超出该函数寿命的对象的引用。也许是局部的static,也许是全局的,也许是f是其成员函数的类的成员变量,等等:

int global = 0;
int&& f() { return std::move(global); }
int&& r = f(); // okay, r is a reference to global, no dangling

或者,如果这没有意义,那么您需要按值返回对象 。您仍然可以参考它。是否:

int f() { return 0; }
int&& r = f(); // okay, lifetime extension
int i = f();   // okay, prvalue elision

一旦我们添加了tuple和结构化绑定的所有复杂性,就会应用相同的基本原理。按值返回本地非静态对象,或按引用返回其他一些对象。但是不要通过引用返回本地非静态对象。


  

最终,我正在尝试创建一个便捷函数,因此不必在每次要创建新所有者时都在函数中键入四行。这是我尝试使用结构化绑定来简化此过程。

为什么不仅仅输入类型?

struct X {
    X() : owner(controller, ancillary, compressor) { }
    X(X const&) = delete;
    X& operator=(X const&) = delete;

    State<Controller> controller;
    State<Ancillary>  ancillary;
    State<Compressor> compressor;
    Owner owner;        
};

// lifetime extension on the X, no copies anywhere
// note that owner is last
auto&& [controller, ancillary, compressor, owner] = X();

// no lifetime extension, but also no copies because
// prvalue elision
auto [controller, ancillary, compressor, owner] = X();

答案 1 :(得分:1)

inline auto makeOwner() {
   struct bundle {
     State<Controller> controller;
     State<Ancillary> ancillary;
     State<Compressor> compressor;
     Owner owner = Owner(controller, ancillary, compressor);
     bundle(bundle  const&)=delete;
     bundle& operator=(bundle  const&)=delete;
   };
   return bundle{};
}

// using the function later

const auto&&[owner, controller, ancillary, compressor] = makeOwner();

在这里我们使用一个事实,即结构,甚至是匿名结构也可以像元组一样被捆绑。

Live example