Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a one-liner to unpack tuple/pair into references?

Tags:

c++

I frequently write snippets like

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

where, for instance, g was declared earlier

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

Problem is, maybe later I actually want x and y to point to the internals of g by reference, and the refactoring is ugly, e.g.

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

or sometimes even worse, for instance if the access is a more complex expression

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

Is there a better refactoring, more in the style of the assignment to tie(..)?

The difficulty as I understand it is that references insist on being initialized exactly at their declaration. So, in possibly other words, is there a way to use tie-like syntax for multiple variable initialization in c++ (this would also make the earlier non reference usage cleaner)?

like image 955
vujazzman Avatar asked Jun 17 '16 08:06

vujazzman


People also ask

How do you unpack a tuple in Python?

Python offers a very powerful tuple assignment tool that maps right hand side arguments into left hand side arguments. THis act of mapping together is known as unpacking of a tuple of values into a norml variable. WHereas in packing, we put values into a regular tuple by means of regular assignment.

How do I unpack a tuple in a list?

Python uses the commas ( , ) to define a tuple, not parentheses. Unpacking tuples means assigning individual elements of a tuple to multiple variables. Use the * operator to assign remaining elements of an unpacking assignment into a list and assign it to a variable.

What is packing and unpacking in tuples?

Tuple packing refers to assigning multiple values into a tuple. Tuple unpacking refers to assigning a tuple into multiple variables.

What is * in Python unpack?

Introduction. Unpacking in Python refers to an operation that consists of assigning an iterable of values to a tuple (or list ) of variables in a single assignment statement. As a complement, the term packing can be used when we collect several values in a single variable using the iterable unpacking operator, * .


2 Answers

Fortunately, C++17 has a solution for exactly this problem, the structured binding declaration. Even the non-reference interface can be improved.

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

The above line declares x, y,z and initializes them with the values of g[i]. Not only is it cleaner, but it could be more efficient for types that are expensive to construct.

To get references to the members of g[i], one can write

auto& [x, y, z] = g[i]; 
like image 155
patatahooligan Avatar answered Oct 04 '22 18:10

patatahooligan


You can automate it with a function so that you don't have to type out 3 (or more) lines:

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

Usage would be:

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 ) }; 
like image 45
user2296177 Avatar answered Oct 04 '22 17:10

user2296177