1

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

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

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();

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

最终,我正在尝试创建一个方便的函数,这样每次我想创建一个新的所有者时,我都不必在函数中键入四行。这是我尝试使用结构化绑定使这更容易。

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

4

2 回答 2

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();
于 2018-08-28T18:10:01.357 回答
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();

在这里,我们使用了结构,即使是匿名结构,也可以像元组一样分拆。

活生生的例子

于 2018-08-28T19:24:23.040 回答