C++ Structured Bindings (C++17): Tuples, Maps, and auto [a,b]

C++ Structured Bindings (C++17): Tuples, Maps, and auto [a,b]

이 글의 핵심

Structured bindings unpack tuples, pairs, arrays, and structs into named variables—map loops, minmax_element, insert results, with lifetime and count rules.

Introduction

Structured bindings (C++17) let you decompose tuples, arrays, structs, and similar types into separate names.

#include <tuple>
#include <iostream>
#include <string>

int main() {
    std::tuple<int, double, std::string> t = {42, 3.14, "Hello"};
    auto [i, d, s] = t;
    std::cout << i << std::endl;
    std::cout << d << std::endl;
    std::cout << s << std::endl;
}

Why use them:

  • Concise multi-variable declarations
  • Readable names in loops
  • Safer type deduction
  • Convenient for maps and multi-return APIs
std::map<std::string, int> m;
for (const auto& [key, value] : m) {
    std::cout << key << ": " << value << '\n';
}

1. Basics

Arrays

int arr[] = {1, 2, 3};
auto [a, b, c] = arr;

Structs

struct Point {
    int x;
    int y;
};

Point p = {10, 20};
auto [x, y] = p;

Tuples / returns

std::tuple<int, double, std::string> getData() {
    return {42, 3.14, "Hello"};
}

int main() {
    auto [i, d, s] = getData();
}

2. References and const

struct Point {
    int x, y;
};

int main() {
    Point p = {10, 20};
    
    auto [x1, y1] = p;       // copies
    auto& [x2, y2] = p;      // aliases
    const auto& [x3, y3] = p;
    
    x2 = 100;  // modifies p.x
}

3. Practical examples

Map iteration

std::map<std::string, int> scores = {
    {"Alice", 90},
    {"Bob", 85},
    {"Charlie", 95}
};

for (const auto& [name, score] : scores) {
    std::cout << name << ": " << score << std::endl;
}

Multiple return values

std::tuple<int, int, int> getRGB() {
    return {255, 128, 64};
}

std::pair<int, int> divmod(int dividend, int divisor) {
    return {dividend / divisor, dividend % divisor};
}

int main() {
    auto [r, g, b] = getRGB();
    auto [quotient, remainder] = divmod(17, 5);
}

minmax_element / insert

std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
auto [minIt, maxIt] = std::minmax_element(v.begin(), v.end());

std::map<std::string, int> m;
auto [it, inserted] = m.insert({"key", 10});

Structs in vectors

struct Person {
    std::string name;
    int age;
    double height;
};

std::vector<Person> people = {
    {"Alice", 25, 165.5},
    {"Bob", 30, 175.0}
};

for (const auto& [name, age, height] : people) {
    std::cout << name << " (" << age << ", " << height << ")\n";
}

4. Common pitfalls

Count mismatch

The number of names must match the tuple/struct size.

Lifetime: reference to subobject of temporary

// Dangerous
// auto& [x, y] = Point{10, 20};

// Safe: copy
auto [x1, y1] = Point{10, 20};

// Safe: bind to named variable
Point p = {10, 20};
auto& [x2, y2] = p;

No explicit types in the binding list

Use auto (or structured binding with auto& / const auto&); you cannot write auto [int x, double y] = ....


5. Patterns

Error handling with pair

std::pair<bool, std::string> parseConfig(const std::string& path) {
    std::ifstream file(path);
    if (!file.is_open()) {
        return {false, "missing file"};
    }
    return {true, "ok"};
}

int main() {
    auto [ok, msg] = parseConfig("config.json");
    if (!ok) {
        std::cerr << msg << std::endl;
        return 1;
    }
}

Range-for modifying values

std::map<std::string, std::vector<int>> data = {
    {"A", {1, 2, 3}},
    {"B", {4, 5, 6}}
};

for (auto& [key, values] : data) {
    values.push_back(0);
}

6. Custom types (tuple protocol)

Implement get<I>(), specialize std::tuple_size / std::tuple_element, then auto [a,b] = myObj works.


7. Student grouping example

See Korean article for full Student / groupByGrade / printStatistics example—same logic in English prose.


Summary

Highlights

  1. Decompose tuple/array/struct-like types
  2. auto / auto& / const auto& control copies vs references
  3. for (const auto& [k,v] : map) is idiomatic
  4. Match element count; watch temporary lifetimes
  5. No runtime overhead inherent to bindings

Supported kinds

KindExample
Arrayint a[3]
Tuple / pairstd::tuple, std::pair
Aggregate structPlain structs with public data
CustomTuple protocol

Next steps

  • Tuple
  • Range-based for
  • auto

  • Structured bindings advanced
  • Range-based for + bindings (series)
  • tuple apply

Practical tips

Debugging

  • Warnings first

Performance

  • Profile

Code review

  • Conventions

Practical checklist

Before coding

  • Right approach?
  • Maintainable?
  • Performance?

While coding

  • Warnings?
  • Edge cases?
  • Errors?

At review

  • Intent?
  • Tests?
  • Docs?

Keywords

C++, structured binding, C++17, auto, destructuring


  • Range-based for + bindings
  • Structured bindings advanced
  • any
  • auto keyword
  • auto type deduction