Возвращает кортеж, который сохраняет ссылки, но копирует r-значения - PullRequest
0 голосов
/ 23 апреля 2020

Мне нужно сделать лямбду, которая возвращает кортеж, который будет использоваться для сортировки вектора объектов. Кортеж собирает коллекцию атрибутов из объекта. Некоторые атрибуты являются ссылками на большие объекты, которые не должны копироваться (f() в приведенном ниже коде), другие являются небольшими r-значениями (g() в приведенном ниже коде). Какой самый простой или самый идиоматический c способ написания лямбды?

#include <vector>
#include <tuple>
#include <algorithm>

struct A {
    std::vector<int> const &f() const;
    int g() const;
};

void example() {
    auto sort_key = [](A const &a) {
        //return std::tuple{a.f(), a.g()}; // copies the vector from f()
        //return std::tie(a.f(), a.g()); // can't bind the int from g()
        //return std::forward_as_tuple(a.f(), a.g()); // returns a reference to the int from g(), which expires when this function returns
        return std::tuple<std::vector<int> const &, int>{a.f(), a.g()}; // works, but requires specifying the types
    };

    std::vector<A> v;
    std::sort(v.begin(), v.end(), [&](A const &a, A const &b) {
        return sort_key(a) < sort_key(b);
    });
}

Мне стыдно сказать, что forward_as_tuple была моей первой попыткой, и после долгого сеанса отладки я понял, что он возвращает int && для второй атрибут, значение, которое выходит за рамки. Писать это таким образом было не по плечу, потому что forward_as_tuple(...) < forward_as_tuple(...), как я понимаю, прекрасно, так как все в одной строке кода, у нас будет продление времени жизни для всех ссылок.

Явное указание типов - ссылка для первый атрибут, значение для второго - при построении кортежа работает, и это то, что я делаю сейчас, но я бы предпочел что-то более чистое. (Ладно, по правде говоря, это не так уж плохо, но я спрашиваю, потому что мне любопытно, есть ли что-нибудь лучше.)

Я мог бы, возможно, создать вспомогательную функцию, вызвать ее forward_references_but_copy_rvalues, но есть ли что-то уже в стандартной библиотеке, которая могла бы сделать это?

...