结构化绑定
本课属于 Coddy C++ 学习旅程的“面向对象编程”单元。第 88 课,共 104 课。
C++17 引入的结构化绑定,可以让你在一条声明中将数组、对、元组或结构体中的多个值解包为单独命名的变量。处理复合数据时,这能让代码更简洁易读。
语法使用 auto,方括号中包含新的变量名:
#include <iostream>
#include <map>
#include <tuple>
int main() {
// 解包 pair
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;
// 在基于范围的 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:定义一个Student结构体,其中包含学生姓名(std::string)、ID(int)和 GPA(double)的公有成员。再创建一个名为createStudent的函数,它接收姓名、ID 和 GPA,并返回一个Student结构体。GradeUtils.h:创建用于处理成绩的工具函数。定义一个
getGradeInfo函数,它接收一个数字成绩(整数),并返回一个包含三个值的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
- 低于 60:“F”,0.0,false
再定义一个
makeScorePair函数,它接收课程名称(std::string)和成绩(int),并返回由这两个值组成的std::pair。main.cpp:读取四个输入:- 学生姓名(字符串)
- 学生 ID(整数)
- 课程名称(字符串)
- 成绩(整数)
在主函数中使用结构化绑定:
- 使用姓名、ID 和占位 GPA 0.0 调用
createStudent。使用结构化绑定将返回的结构体解包为单独的变量,然后打印:Student: [name] (ID: [id]) - 使用课程名称和成绩调用
makeScorePair。使用结构化绑定解包这个键值对,然后打印:Course: [course], Score: [score] - 使用成绩调用
getGradeInfo。使用结构化绑定解包元组中的三个元素,然后打印:(及格时打印 "yes",不及格时打印 "no")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: 用姓名、ID 和占位 GPA 值 0.0 调用 createStudent
// 使用结构化绑定解包结构体:auto [name, id, gpa] = ...
// 输出:Student: [name] (ID: [id])
// TODO: 用课程名称和分数调用 makeScorePair
// 使用结构化绑定解包 pair:auto [course, sc] = ...
// 输出:Course: [course], Score: [score]
// TODO: 用分数调用 getGradeInfo
// 使用结构化绑定解包元组:auto [letter, points, passing] = ...
// 输出:
// Grade: [letter]
// Points: [points]
// Passing: [yes/no](如果 passing 为 true,输出 "yes";否则输出 "no")
return 0;
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C++ 在线编译器