cpp/language/structured binding

Binds the specified names to subobjects or elements of the initializer.

Like a reference, a structured binding is an alias to an existing object. Unlike a reference, a structured binding does not have to be of a reference type.

A structured binding declaration introduces all identifiers in the as names in the surrounding scope and binds them to subobjects or elements of the object denoted by. The bindings so introduced are called structured bindings.

A structured binding declaration first introduces a uniquely-named variable (here denoted by ) to hold the value of the initializer, as follows:
 * If has array type  and no  is present, then  has type cv, where cv is the cv-qualifiers in the  sequence, and each element of  is copy- (for ) or direct- (for ) initialized from the corresponding element of.
 * Otherwise is defined as if by using its name instead of    in the declaration.

We use to denote the type of the expression. (In other words, is the equivalent of .)

A structured binding declaration then performs the binding in one of three possible ways, depending on :
 * Case 1: if is an array type, then the names are bound to the array elements.
 * Case 2: if is a non-union class type and  is a complete type with a member named  (regardless of the type or accessibility of such member), then the "tuple-like" binding protocol is used.
 * Case 3: if is a non-union class type but  is not a complete type, then the names are bound to the accessible data members of.

Each of the three cases is described in more detail below.

Each structured binding has a referenced type, defined in the description below. This type is the type returned by when applied to an unparenthesized structured binding.

Case 1: binding an array
Each identifier in the becomes the name of an lvalue that refers to the corresponding element of the array. The number of identifiers must equal the number of array elements.

The referenced type for each identifier is the array element type. Note that if the array type is cv-qualified, so is its element type.

Case 2: binding a tuple-like type
The expression must be a well-formed integer constant expression, and the number of identifiers must equal.

For each identifier, a variable whose type is "reference to " is introduced: lvalue reference if its corresponding initializer is an lvalue, rvalue reference otherwise. The initializer for the i-th variable is
 * , if lookup for the identifier in the scope of  by class member access lookup finds at least one declaration that is a function template whose first template parameter is a non-type parameter
 * Otherwise,, where is looked up by  only, ignoring non-ADL lookup.

In these initializer expressions, is an lvalue if the type of the entity  is an lvalue reference (this only happens if the  is  or if it is  and the initializer expression is an lvalue) and an xvalue otherwise (this effectively performs a kind of perfect forwarding),  is a  prvalue, and  is always interpreted as a template parameter list.

The variable has the same as.

The identifier then becomes the name of an lvalue that refers to the object bound to said variable.

The referenced type for the i-th identifier is.

Case 3: binding to data members
Every non-static data member of must be a direct member of  or the same base class of, and must be well-formed in the context of the structured binding when named as. may not have an anonymous union member. The number of identifiers must equal the number of non-static data members.

Each identifier in becomes the name of an lvalue that refers to the next member of  in declaration order (bit-fields are supported); the type of the lvalue is that of, where  refers to the i$th$ member.

The referenced type of the i-th identifier is the type of if it is not a reference type, or the declared type of  otherwise.