Возвращение кортежа локальных объектов - PullRequest
0 голосов
/ 28 августа 2018

Как использовать структурированное связывание и кортежи для возврата объектов, локальных для функции?

В функции я создаю локальные объекты, которые ссылаются друг на друга, и я хочу вернуть эти объекты в кортеже и использовать структурированное связывание для их идентификации при каждом вызове функции. В настоящее время у меня есть это:

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

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

В конечном итоге я пытаюсь создать вспомогательную функцию, чтобы мне не приходилось вводить четыре строки в функции каждый раз, когда я хочу создать нового владельца. Это моя попытка использовать структурированное связывание, чтобы сделать это проще.

EDIT: Я должен отметить, что я хочу, чтобы привязки в последней строке ссылались на объекты внутри владельца. Итак, копий недостаточно.

Ответы [ 2 ]

0 голосов
/ 28 августа 2018
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();

здесь мы используем тот факт, что структуры, даже анонимные, могут быть разделены как кортежи.

Живой пример .

0 голосов
/ 28 августа 2018

Я хочу, чтобы привязки в последней строке ссылались на объекты внутри владельца.

Давайте проигнорируем все новые языковые функции и вернемся к основам. Как вы ожидаете, что это будет работать?

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