CppStructured Bindings

Structured Bindings

C++17 introduced structured bindings: a concise syntax for unpacking the elements of a pair, tuple, array, or struct into individually named variables in a single declaration. Instead of writing .first/.second or std::get<0>() every time you touch a piece of a compound value, you give each piece a meaningful name up front.
Before and after

Unpacking a pair: old way vs structured bindings

CPP
#include <iostream>
#include <map>
#include <utility>

std::pair<int, std::string> lookupUser() {
    return {42, "Ada"};
}

int main() {
    // Before C++17: verbose access through .first / .second
    auto result = lookupUser();
    int id = result.first;
    std::string name = result.second;
    std::cout << id << ": " << name << "\n";

    // C++17 structured bindings: unpack directly into named variables
    auto [userId, userName] = lookupUser();
    std::cout << userId << ": " << userName << "\n";

    return 0;
}
Iterating a map
The single most common and best-loved use of structured bindings in everyday modern C++ is iterating a std::map (or std::unordered_map). Before C++17, every element in a map iteration was a std::pair<const Key, Value>, forcing you to write entry.first and entry.second throughout the loop body. Structured bindings let you name the key and value directly.

Old vs new map iteration

CPP
#include <iostream>
#include <map>
#include <string>

int main() {
    std::map<std::string, int> inventory = {
        {"apples", 12}, {"bananas", 5}, {"cherries", 30}
    };

    // Before C++17
    for (const auto& entry : inventory) {
        std::cout << entry.first << ": " << entry.second << "\n";
    }

    // With structured bindings — much more readable
    for (const auto& [item, count] : inventory) {
        std::cout << item << ": " << count << "\n";
    }

    return 0;
}
Unpacking a custom struct

Structured bindings also work directly on the public data members of a plain struct, in declaration order, with no extra code needed on the struct itself.

Structured bindings with a custom struct

CPP
#include <iostream>

struct Point3D {
    double x;
    double y;
    double z;
};

Point3D midpoint(const Point3D& a, const Point3D& b) {
    return { (a.x + b.x) / 2, (a.y + b.y) / 2, (a.z + b.z) / 2 };
}

int main() {
    Point3D a{0.0, 0.0, 0.0};
    Point3D b{4.0, 8.0, 12.0};

    auto [mx, my, mz] = midpoint(a, b);
    std::cout << "Midpoint: (" << mx << ", " << my << ", " << mz << ")\n";

    return 0;
}
Works with tuples too
Structured bindings unpack std::tuple the same way they unpack pairs and structs: auto [a, b, c] = myTuple; replaces repeated calls to std::get<0>(myTuple), std::get<1>(myTuple), and so on. You can also bind by reference (auto& [a, b] = pair;) to modify the original object's elements in place, instead of copying them.
  • auto [a, b] = expr; unpacks a pair, tuple, array, or struct into named variables in one declaration.

  • The most common real-world use is iterating a map: for (const auto& [key, value] : myMap).

  • It works on plain structs automatically, binding members in declaration order.

  • Bind by reference with auto& [...] to mutate the original elements rather than copy them.