Structured Bindings
Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 88 of 104.
Structured bindings, introduced in C++17, let you unpack multiple values from arrays, pairs, tuples, or structs into individual named variables in a single declaration. This makes code cleaner and more readable when working with composite data.
The syntax uses auto with square brackets containing the new variable names:
#include <iostream>
#include <map>
#include <tuple>
int main() {
// Unpacking a pair
std::pair<std::string, int> person{"Alice", 25};
auto [name, age] = person;
std::cout << name << " is " << age << "\n";
// Unpacking a tuple
std::tuple<int, double, char> data{42, 3.14, 'X'};
auto [num, pi, letter] = data;
// Unpacking in range-based for loops
std::map<std::string, int> scores{{"Bob", 90}, {"Carol", 85}};
for (const auto& [student, score] : scores) {
std::cout << student << ": " << score << "\n";
}
}Structured bindings also work with arrays and custom structs that have public members:
struct Point {
double x;
double y;
};
Point getOrigin() { return {0.0, 0.0}; }
int main() {
auto [x, y] = getOrigin();
int arr[3] = {1, 2, 3};
auto [a, b, c] = arr;
}You can use auto& or const auto& to bind by reference, avoiding copies and allowing modification of the original values when needed. This feature is especially useful when iterating over STL containers or handling functions that return multiple values.
Challenge
EasyLet's build a student grade analyzer that showcases the power of structured bindings. You'll create a system that processes student records and course data, using structured bindings to elegantly unpack pairs, tuples, and structs throughout your code.
You'll organize your code across three files:
Student.h: Define aStudentstruct with public members for the student's name (std::string), ID (int), and GPA (double). Also create a function calledcreateStudentthat takes a name, ID, and GPA, and returns aStudentstruct.GradeUtils.h: Create utility functions for grade processing.Define a function
getGradeInfothat takes a numeric score (integer) and returns astd::tuplecontaining three values: the letter grade (std::string), the grade points (double), and whether it's passing (bool). Use this grading scale:- 90+ : "A", 4.0, true
- 80-89: "B", 3.0, true
- 70-79: "C", 2.0, true
- 60-69: "D", 1.0, true
- Below 60: "F", 0.0, false
Also define a function
makeScorePairthat takes a course name (std::string) and score (int), returning astd::pairof those values.main.cpp: Read four inputs:- Student name (string)
- Student ID (integer)
- Course name (string)
- Score (integer)
Use structured bindings throughout your main function:
- Call
createStudentwith the name, ID, and a placeholder GPA of 0.0. Use structured bindings to unpack the returned struct into individual variables, then print:Student: [name] (ID: [id]) - Call
makeScorePairwith the course name and score. Use structured bindings to unpack the pair, then print:Course: [course], Score: [score] - Call
getGradeInfowith the score. Use structured bindings to unpack all three tuple elements, then print:(Print "yes" if passing is true, "no" if false)Grade: [letter] Points: [points] Passing: [yes/no]
For example, with inputs Alice, 1001, Math, and 85:
Student: Alice (ID: 1001)
Course: Math, Score: 85
Grade: B
Points: 3
Passing: yesWith inputs Bob, 2002, Physics, and 55:
Student: Bob (ID: 2002)
Course: Physics, Score: 55
Grade: F
Points: 0
Passing: noRemember to include <tuple> and <utility> where needed. The key insight is how structured bindings let you unpack composite types—pairs, tuples, and structs—into named variables in a single, readable declaration.
Cheat sheet
Structured bindings (C++17) allow unpacking multiple values from arrays, pairs, tuples, or structs into individual named variables in a single declaration.
Basic syntax uses auto with square brackets:
auto [var1, var2, ...] = composite_object;Unpacking a std::pair:
std::pair<std::string, int> person{"Alice", 25};
auto [name, age] = person;Unpacking a std::tuple:
std::tuple<int, double, char> data{42, 3.14, 'X'};
auto [num, pi, letter] = data;Using structured bindings in range-based for loops with containers like std::map:
std::map<std::string, int> scores{{"Bob", 90}, {"Carol", 85}};
for (const auto& [student, score] : scores) {
std::cout << student << ": " << score << "\n";
}Unpacking structs with public members:
struct Point {
double x;
double y;
};
Point getOrigin() { return {0.0, 0.0}; }
auto [x, y] = getOrigin();Unpacking arrays:
int arr[3] = {1, 2, 3};
auto [a, b, c] = arr;Use auto& or const auto& to bind by reference, avoiding copies and allowing modification of original values:
auto& [x, y] = point; // Can modify original
const auto& [name, age] = person; // Read-only referenceTry it yourself
#include <iostream>
#include <string>
#include "Student.h"
#include "GradeUtils.h"
int main() {
// Read inputs
std::string studentName;
int studentId;
std::string courseName;
int score;
std::cin >> studentName;
std::cin >> studentId;
std::cin >> courseName;
std::cin >> score;
// TODO: Call createStudent with name, id, and placeholder GPA of 0.0
// Use structured bindings to unpack the struct: auto [name, id, gpa] = ...
// Print: Student: [name] (ID: [id])
// TODO: Call makeScorePair with course name and score
// Use structured bindings to unpack the pair: auto [course, sc] = ...
// Print: Course: [course], Score: [score]
// TODO: Call getGradeInfo with the score
// Use structured bindings to unpack the tuple: auto [letter, points, passing] = ...
// Print:
// Grade: [letter]
// Points: [points]
// Passing: [yes/no] (print "yes" if passing is true, "no" if false)
return 0;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesC++ Build & CompilationHeader Files & Source FilesNamespaces & ScopeIntroduction to OOP in C++Classes vs ObjectsThe 'this' PointerMethods (Member Functions)Attributes (Data Members)Ctors & Dtors BasicsRecap - Simple Calculator4Class Properties
Instance vs Static MembersGetters and SettersConst Member FunctionsMutable KeywordStatic Methods and VariablesFriend Functions & ClassesRecap - Bank Account Manager7Inheritance
Basic InheritanceInheritance Access LevelsCtor & Dtor Call OrderMethod OverridingVirtual Functions & VTableMultiple InheritanceVirtual InheritanceRecap - Employee Hierarchy2Memory Management
Stack vs Heap MemoryPointers and ReferencesDynamic Memory (new/delete)Smart Pointers in C++RAII in C++Recap - Dynamic Array Manager5Encapsulation
Access Specifiers in C++Access Specifiers In DepthInformation HidingStruct vs ClassNested & Inner ClassesRecap - Student Records System8Polymorphism
Compile vs Runtime PolymorphFunction OverloadingVirtual Functions RevisitedPure Virtual FunctionsAbstract ClassesInterface Design in C++Dynamic Casting & RTTIRecap - Shape Calculator3Constructors & Destructors
Default ConstructorParameterized ConstructorCopy ConstructorMove ConstructorConstructor Init ListsDelegating ConstructorsDestructor Deep DiveRule of Three / Five / ZeroRecap - String Class6Operator Overloading
Intro to Operator OverloadArithmetic Operator OverloadComparison Operator OverloadStream OperatorsAssignment Operator Overload[] and () Operator OverloadType Conversion OperatorsRecap - Matrix Class9Templates
Function TemplatesClass TemplatesTemplate SpecializationVariadic TemplatesSFINAE & Type Traits BasicsRecap - Generic Container12Modern C++ Features
Move Semantics & RvaluesPerfect ForwardingLambda Expressions In Depthstd::function & std::bindconstexpr and constevalStructured Bindingsoptional, variant, any