I'm trying to understand structured binding introduced in C++17. The explanation on cppreference is not obvious to me, but it looks like
cv-auto ref-operator [x, y, z] = ...
is roughly equivalent to (not to consider array case)
cv-auto ref-operator unique_name = ...
#define x unique_name.member_a
#define y unique_name.member_b
#define z unique_name.member_c
The key point here is that x y z
are not independently defined variables, but just aliases of the return value members. And cv-auto ref-operator
applies to the return value, not the aliases (the syntax may be misleading here). For instance, see the cppreference example
float x{};
char y{};
int z{};
std::tuple<float&,char&&,int> tpl(x,std::move(y),z);
const auto& [a,b,c] = tpl;
// a names a structured binding of type float& that refers to x
// b names a structured binding of type char&& that refers to y
// c names a structured binding of type const int that refers to the 3rd element of tpl
If a b c
are independently defined variables, with const auto&
applying to them, c
cannot be of type const int
.
From a practical point of view, what are the key points this analogy failed to catch?
It might be insightful to consider this from another perspective.
In C++ we already had variables, objects with a name
int a = 5
and objects that aren't variables and do not have a name:*new int
. Structured bindings are a way to have names for all parts of a variable, while the whole variable has no explicit name. So it's the combination[x,y,z]
that together names an variable with three members.Importantly, they together name an object, so the compiler actually has to layout the object. Independent variables can be placed independently on the stack. but with structured bindings the compiler cannot do so (except for the normal
as-if
rule)So when we consider the combination
[x y z]
as the name of the variable, it's clear thatauto const& [x y z]
makes the combination aconst&
variable.We then have to consider what exactly the individual names
x
,y
andz
mean. Your question summarizes them asThat's a bit tricky. Where does
member_a
come from? It appears thatunique_name
has amember_a
. You already excluded the array case, which has[0]
. Tuples haveget<0>(tpl)
. There might very well be amember_a
behind theget<0>
, but the namemember_a
could be private.member_a
could also be less const-qualified thanget<0>
.But yes, for the most simple case, a simple
struct
without bitfields, there will indeed be a correspondingmember_a
.