Skip to Content
Course content

89: Structured Bindings

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you've ordered a meal kit. When the box arrives, it contains a steak, a bunch of asparagus, and a potato. You could refer to them as "item one," "item two," and "item three," but that's a tedious way to cook. Instead, the moment you open the box, you mentally assign them names: "This is the protein, this is the veg, and this is the starch." You've effectively "unpacked" the kit into distinct, named variables that make sense for the task at hand.

In C++17, structured bindings do exactly this for your data structures. Instead of accessing members of a pair, tuple, or struct through generic indices or member names, you can unpack them directly into individual variables in a single line of code.

Stop using .first and .second

If you've been using std::pair or std::tuple, you know the pain of my_pair.first and my_pair.second. It's technically correct, but it tells the reader nothing about what the data actually represents. I've spent way too many hours debugging code where I forgot if .first was the ID or the Value.

Here is how we handle that now:

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

std::tuple<int, std::string, double> get_employee_data() {
    return {101, "Alice Smith", 75000.0};
}

int main() {
    // The "old" way: verbose and vague
    auto emp = get_employee_data();
    std::cout << std::get<0>(emp) << " " << std::get<1>(emp) << "\n";

    // The structured binding way: clean and descriptive
    auto [id, name, salary] = get_employee_data();
    std::cout << "ID: " << id << ", Name: " << name << ", Salary: " << salary << "\n";
}

Notice the auto [id, name, salary] syntax. C++ looks at the return type of the function, sees it's a tuple of three elements, and maps them directly to those three variables. It's a massive win for readability.

Unpacking your own custom structs

Structured bindings aren't just for the Standard Library containers. They work with any simple struct or class with public data members. This is incredibly useful when you have a small "Data Transfer Object" (DTO) that you just want to break apart quickly.

struct Point {
    double x;
    double y;
};

Point get_origin() { return {0.0, 0.0}; }

void move_point() {
    Point p = get_origin();
    auto [posX, posY] = p; // Unpacks p.x into posX and p.y into posY
    
    std::cout << "X is " << posX << " and Y is " << posY << "\n";
}

Dealing with references and modifications

One thing to keep in mind: auto [a, b] = ... creates copies of the values. If you're unpacking a large object or you actually want to modify the original data inside the structure, you need to use auto& or const auto&.

I usually default to const auto& unless I know I need to change the value. It prevents unnecessary copying of strings or vectors that might be hiding inside that tuple.

struct Player {
    std::string name;
    int score;
};

void update_score(Player& p) {
    // Use auto& to modify the original player object
    auto& [name, score] = p;
    score += 10; 
    std::cout << name << " now has " << score << " points!\n";
}

Just remember that the variables inside the brackets are not independent variables in the way you might think—they are aliases to the members of the hidden object being unpacked. This is why auto& works so seamlessly.




📋 Practical Task

Exercise: The Weather Station Data Parser

You are writing a module for a weather station. The station provides a function that returns a std::tuple containing the city name, the current temperature, and the humidity percentage. Currently, the code uses std::get, which is making it hard to read.

Your Task: Refactor the print_weather_report function to use structured bindings to unpack the tuple returned by fetch_weather_data. Ensure that you use a const auto& binding to avoid unnecessary copying of the city name string.

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

// This function simulates fetching data from a sensor
std::tuple<std::string, double, int> fetch_weather_data() {
    return {"Seattle", 14.5, 82};
}

void print_weather_report() {
    auto data = fetch_weather_data();
    
    // TODO: Replace the following lines with a single line of structured bindings
    std::string city = std::get<0>(data);
    double temp = std::get<1>(data);
    int humidity = std::get<2>(data);

    std::cout << "City: " << city << "\nTemp: " << temp << "C\nHumidity: " << humidity << "%\n";
}

int main() {
    print_weather_report();
    return 0;
}
Rating
0 0

There are no comments for now.

to be the first to leave a comment.