Skip to main content
Tuple-like binding, formally defined in C++17 as structured binding, is a language mechanism that unpacks the subobjects of an array, tuple-like object, or aggregate class into distinct, named identifiers within a single declaration. Rather than creating independent variables, the compiler generates a hidden anonymous entity initialized by the right-hand expression, and the declared identifiers serve as aliases to the subobjects of that hidden entity.

Syntax

Structured bindings support assignment, direct-list, and direct initialization:
  • cv-auto: The auto keyword, optionally modified by const or volatile.
  • ref-operator: Optional & (lvalue reference) or && (rvalue reference).
  • identifier-list: A comma-separated list of names to bind to the subobjects.
  • expression: The object being unpacked.

The Hidden Object Mechanism

When a structured binding is declared, the compiler conceptually transforms it. The cv-qualifiers and ref-operator apply to the hidden object, not directly to the individual identifiers.

Binding Protocols

The compiler determines how to unpack the expression by evaluating three distinct protocols in a strict sequence.

1. Array Binding

If the expression is an array type, the identifiers bind directly to the array elements. The number of identifiers must exactly match the array size.

2. Tuple-Like Protocol

If the expression’s type E satisfies the tuple-like protocol, the compiler uses standard library templates and getter functions to extract the values. This is triggered if std::tuple_size<E> is a complete type. To satisfy this protocol, a type must provide:
  1. std::tuple_size<E>::value: A compile-time constant dictating the number of elements.
  2. std::tuple_element<I, E>::type: A type trait defining the type of the I-th element.
  3. get<I>(e): A template function to extract the value, resolved either as a member function e.get<I>() or via Argument-Dependent Lookup (ADL). A robust tuple-like implementation requires const and rvalue overloads of get to support all binding contexts.
Custom Tuple-Like Implementation:

3. Data Member Binding

If the type is not an array and does not implement the tuple-like protocol, the compiler falls back to binding directly to the public, non-static data members of the class or struct.
  • All non-static data members must be declared in the same class (either the type itself or a single unambiguous base class).
  • The number of identifiers must exactly match the number of non-static data members.
  • The binding occurs in declaration order.

decltype Behavior

Because structured bindings are aliases rather than standard variables, applying decltype to a bound identifier yields the referenced type specified by the tuple-like protocol (std::tuple_element_t) or the exact declared type of the data member, preserving its referenceness and cv-qualifiers relative to the hidden object.
Tired of Poor C++ Skills? Fix That With Deep Grasping!Learn More