Подтвердить что ты не робот

Есть ли один-лайнер для распаковки кортежа/пары в ссылки?

Я часто пишу фрагменты типа

int x,y,z; tie(x,y,z) = g[19];

где, например, g было объявлено ранее

vector<tuple<int,int,int>> g(100);

Проблема в том, что, возможно, позже я хочу, чтобы x и y указывали на внутренности g по ссылке, а рефакторинг был уродлив, например

int &x = get<0>(g[19]);
int &y = get<1>(g[19]);
int &z = get<2>(g[19]);

или иногда даже хуже, например, если доступ является более сложным выражением

tuple<int,int,int> &p = g[19]; // if the rhs was actually more complicated
int &x = get<0>(p);
int &y = get<1>(p);
int &z = get<2>(p);

Есть ли лучший рефакторинг, больше в стиле задания для привязки (..)?

Трудность, насколько я понимаю, заключается в том, что ссылки настаивают на инициализации именно в их объявлении. Итак, возможно, другими словами, есть ли способ использовать синтаксис tie -like для множественной инициализации переменных в С++ (это также сделает более раннее использование не ссылочного использования)?

4b9b3361

Ответ 1

Вы можете автоматизировать его с помощью функции, так что вам не нужно набирать 3 (или более) строки:

template <class... Ts, std::size_t... Is, class Tuple>
decltype( auto ) tie_from_specified( std::index_sequence<Is...>, Tuple& tuple )
{
    return std::tuple<Ts...>{ std::get<Is>( tuple )... };
}

template <class... Ts, class Tuple>
decltype( auto ) tie_from( Tuple& tuple )
{
    return tie_from_specified<Ts...>( std::make_index_sequence<sizeof...( Ts )>{}, tuple );
}

Использование:

int x{ 2 };
std::tuple<int, int&, int> g19( 1, x, 3 );

// new tuple: ref to get<0>( g19 ), value of get<1>( g19 ), ref to get<2>( g19 )
auto t0{ tie_from<int&, int, int&>( g19 ) };

// new tuple: ref to get<0>( g19 ), ref to get<2>( g19 )
auto t1{ tie_from_specified<int&, int&>( std::index_sequence<0, 2>{}, g19 ) };

Ответ 2

Вы можете написать структуру для хранения ссылок:

struct vector3d
{
    vector3d(std::tuple<int, int, int>& tuple)
      : x(std::get<0>(tuple)),
        y(std::get<1>(tuple)),
        z(std::get<2>(tuple))
    {}

    int& x;
    int& y;
    int& z;
};

И затем используйте его следующим образом:

vector3d vec(g[6]);
// do sth with vec.x or vec.y or vec.z or all together :)

Ответ 3

К счастью, у С++ 17 есть решение именно этой проблемы, структурированная декларация привязки. Даже интерфейс без ссылки может быть улучшен.

auto[x, y, z] = g(i);

Вышеупомянутая строка объявляет x, y, z и инициализирует их значениями g(i). Он не только более чист, но и может быть более эффективным для типов, которые дороги построить.

Чтобы получить ссылки на члены g(i), можно написать

auto& [x, y, z] = g(i);