std::ranges::sort 的投影参数支持按结构体特定成员排序:一、用成员指针(如 &Person::age);二、用 lambda 实现转换(如忽略大小写);三、用 std::mem_fn 绑定 getter;四、用 lambda 处理嵌套字段;五、对 const 成员须用 lambda 返回引用。

如果您需要对包含多个成员的复杂结构体进行排序,但仅依据其中某个特定成员的值,std::ranges::sort 的投影(projection)参数可直接提取该成员参与比较。以下是实现此功能的具体步骤:
一、定义结构体并使用成员指针作为投影
投影函数允许在不修改结构体定义或编写额外比较器的情况下,将排序逻辑绑定到指定成员。使用指向成员的指针(如 &Person::age)可让 std::ranges::sort 自动提取每个元素的对应字段进行比较。
1、声明结构体 Person,包含 name 和 age 两个公有成员。
2、创建 std::vector
3、调用 std::ranges::sort(v, {}, &Person::age),第三个参数为投影,表示按 age 升序排列。
4、编译时需启用 C++20 标准,并包含
二、使用 lambda 表达式实现动态投影
当需对成员进行转换后再比较(例如忽略大小写排序字符串),lambda 可封装任意表达式作为投影。该方式不依赖成员指针语法,灵活性更高,且支持临时计算。
1、定义结构体 Book,含 title(std::string)和 price(double)成员。
2、构造 std::vector
3、调用 std::ranges::sort(books, {}, [](const Book& b) { return b.title; }),投影返回 title 字符串用于字典序比较。
4、若需忽略大小写,可将 lambda 内部替换为:[&](const Book& b) { std::string lower = b.title; std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); return lower; }。
三、使用 std::mem_fn 绑定成员函数作为投影
当结构体提供访问成员的 const 成员函数(如 getter),std::mem_fn 可将其适配为可调用对象,作为投影传入。这种方式增强封装性,适用于私有成员场景。
1、定义类 Student,将 score 设为 private,并提供 public const 成员函数 get_score()。
2、使用 std::vector
3、调用 std::ranges::sort(students, {}, std::mem_fn(&Student::get_score))。
4、确保 get_score() 声明为 const,否则 std::mem_fn 在遍历时可能触发编译错误。
四、组合多个投影实现嵌套字段排序
对于嵌套结构(如 Address 内嵌于 Person 中),可通过链式调用或复合 lambda 提取深层字段。投影本身不支持多级点号语法,必须显式展开访问路径。
1、定义结构体 Address 含 city(std::string),结构体 Person 含 addr(Address)成员。
2、构造 std::vector
3、调用 std::ranges::sort(people, {}, [](const Person& p) { return p.addr.city; })。
4、若需先按 city 排序、city 相同时按 name 排序,需改用自定义比较器而非单一投影,此时投影不再适用,应切换至 std::ranges::sort 的二元谓词参数形式。
五、处理 const 成员或不可默认构造类型的投影
当结构体成员为 const 或无默认构造函数时,直接取地址(如 &T::member)可能失败。此时必须借助 lambda 显式引用,避免隐式拷贝或构造尝试。
1、定义结构体 Config,含 const std::string version 成员。
2、声明 std::vector
3、使用 lambda 投影:[](const Config& c) -> const std::string& { return c.version; },明确返回 const 引用。
4、禁止使用 &Config::version,因 const 成员指针在某些标准库实现中不被 ranges 算法接受。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











