有没有一个单行将解包元组/对引用到引用中?

时间:2016-06-17 08:06:24

标签: c++

我经常写一些像

这样的片段
int x,y,z; tie(x,y,z) = g[19];

例如,g之前已声明

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

问题是,也许以后我实际上希望xy通过引用指向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);

是否有更好的重构,更多的是分配方式(...)?

我理解的困难是参考文献坚持要初始化exactly at their declaration。所以,换句话说,有没有办法在c ++中使用tie - 类似于多变量初始化的语法(这也会使早期的非参考用法更清晰)?

3 个答案:

答案 0 :(得分:6)

您可以使用一个功能自动化它,这样您就不必输入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 ) };

答案 1 :(得分:5)

幸运的是,C ++ 17有一个解决这个问题的解决方案structured binding declaration。甚至可以改进非参考界面。

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

上面的行声明了x,y,z,并使用g[i]的值初始化它们。它不仅更清洁,而且对于构造昂贵的类型来说可能更有效。

要获得对g[i]成员的引用,可以写

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

答案 2 :(得分:0)

您可以编写一个结构来存储引用:

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 :)