Структурированные привязки
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 88 из 104.
Structured bindings, появившиеся в C++17, позволяют распаковывать несколько значений из массивов, пар, кортежей или структур в отдельные именованные переменные в одном объявлении. Это делает код более чистым и понятным при работе с составными данными.
В синтаксисе используется auto с квадратными скобками, содержащими новые имена переменных:
#include <iostream>
#include <map>
#include <tuple>
int main() {
// Распаковка пары
std::pair<std::string, int> person{"Alice", 25};
auto [name, age] = person;
std::cout << name << " is " << age << "\n";
// Распаковка кортежа
std::tuple<int, double, char> data{42, 3.14, 'X'};
auto [num, pi, letter] = data;
// Распаковка в range-based for-циклах
std::map<std::string, int> scores{{"Bob", 90}, {"Carol", 85}};
for (const auto& [student, score] : scores) {
std::cout << student << ": " << score << "\n";
}
}Структурированные привязки также работают с массивами и пользовательскими структурами, у которых есть общедоступные члены:
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;
}Вы можете использовать auto& или const auto&, чтобы связать по ссылке, избегая копирования и позволяя изменять исходные значения при необходимости. Эта возможность особенно полезна при переборе контейнеров STL или обработке функций, возвращающих несколько значений.
Задание
ЛегкоДавайте создадим анализатор оценок студентов, демонстрирующий возможности структурированных привязок. Вы создадите систему, которая обрабатывает записи студентов и данные курсов, используя структурированные привязки для элегантной распаковки пар, кортежей и структур по всему коду.
Вы организуете код в трёх файлах:
Student.h: Define структуруStudentс открытыми членами для имени студента (std::string), идентификатора (int) и GPA (double). Также создайте функцию с именемcreateStudent, которая принимает имя, идентификатор и GPA и возвращает структуруStudent.GradeUtils.h: Создайте вспомогательные функции для обработки оценок.Define функцию
getGradeInfo, которая принимает numeric оценку (целое число) и возвращаетstd::tuple, содержащий три значения: буквенную оценку (std::string), баллы за оценку (double) и признак того, является ли оценка проходной (bool). Используйте следующую шкалу оценок:- 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
Также Define функцию
makeScorePair, которая принимает название курса (std::string) и оценку (int), возвращаяstd::pairиз этих значений.main.cpp: Считайте четыре входных значения:- Имя студента (строка)
- Идентификатор студента (целое число)
- Название курса (строка)
- Оценка (целое число)
Используйте структурированные привязки на протяжении всей функции main:
- Вызовите
createStudentс именем, идентификатором и placeholder GPA, равным 0.0. Используйте структурированные привязки, чтобы распаковать возвращённую структуру в отдельные переменные, а затем выведите:Student: [name] (ID: [id]) - Вызовите
makeScorePairс названием курса и оценкой. Используйте структурированные привязки, чтобы распаковать пару, а затем выведите:Course: [course], Score: [score] - Вызовите
getGradeInfoс оценкой. Используйте структурированные привязки, чтобы распаковать все три элемента кортежа, а затем выведите:(Выведите "yes", если passing имеет значение true, и "no", если false)Grade: [letter] Points: [points] Passing: [yes/no]
Например, для входных данных Alice, 1001, Math и 85:
Student: Alice (ID: 1001)
Course: Math, Score: 85
Grade: B
Points: 3
Passing: yesДля входных данных Bob, 2002, Physics и 55:
Student: Bob (ID: 2002)
Course: Physics, Score: 55
Grade: F
Points: 0
Passing: noНе забудьте добавить <tuple> и <utility> там, где это необходимо. Основная идея заключается в том, как структурированные привязки позволяют распаковывать составные типы, пары, кортежи и структуры в именованные переменные в одном понятном объявлении.
Попробуйте сами
#include <iostream>
#include <string>
#include "Student.h"
#include "GradeUtils.h"
int main() {
// Прочитать входные данные
std::string studentName;
int studentId;
std::string courseName;
int score;
std::cin >> studentName;
std::cin >> studentId;
std::cin >> courseName;
std::cin >> score;
// TODO: Вызвать createStudent с name, id и временным GPA 0.0
// Используйте структурированные привязки для распаковки структуры: auto [name, id, gpa] = ...
// Вывести: Student: [name] (ID: [id])
// TODO: Вызвать makeScorePair с названием курса и score
// Используйте структурированные привязки для распаковки пары: auto [course, sc] = ...
// Вывести: Course: [course], Score: [score]
// TODO: Вызвать getGradeInfo с score
// Используйте структурированные привязки для распаковки кортежа: auto [letter, points, passing] = ...
// Вывести:
// Grade: [letter]
// Points: [points]
// Passing: [yes/no] (выведите "yes", если passing равно true, "no", если false)
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнер12Возможности современного C++
Семантика перемещения и RvaluesИдеальная передача (Perfect Forwarding)Лямбда-выражения в деталяхstd::function и std::bindconstexpr и constevalСтруктурированные привязкиoptional, variant, anyПотренируйтесь самостоятельно: Онлайн-компилятор C++