std::identity是c++20中用于投影的零开销恒等映射,必须以std::identity{}形式使用;它类型安全、constexpr友好、完美转发,语义明确优于手写lambda。

std::identity 在 C++20 中不是“用来凑数的”,而是为算法投影(projection)提供零开销、类型安全的恒等映射——当你不需要变换元素,但接口强制要求传入 projection 参数时,它就是最直接、最明确的选择。
什么时候必须用 std::identity?
当调用带 projection 参数的算法(如 std::ranges::sort、std::ranges::max_element、std::ranges::find_if 等),而你本意就是按元素本身比较或查找,又不想写 [](const auto& x) { return x; } 这种冗余 lambda 时,std::identity{} 就是标准答案。
- 例如
std::ranges::sort(v, std::less{}, std::identity{}):显式声明“排序依据就是元素自身”,比省略projection更清晰(尤其在重载多、参数顺序易混淆的场景) - 若误传
std::identity(不带{})会编译失败:error: no matching function for call to 'sort(..., std::identity)'—— 它是个类模板,必须构造实例 - 不能用
std::identity()(带括号的函数调用语法),那是 C++17 的废弃用法;C++20 要求std::identity{}
std::identity 和手写 lambda 的实际差异
表面上都是“返回原值”,但语义和行为有关键区别:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
std::identity{}是字面量类型(is_literal_type_v为true),可参与constexpr上下文;lambda 若捕获或含非字面量操作则不行 - 它对右值也完美转发:
std::identity{}(std::string{"hello"})返回std::string&&,而[](auto&& x) { return x; }默认按值返回(除非显式写return static_cast<decltype>(x);</decltype>) - 模板推导更稳定:lambda 可能因重载集引发 SFINAE 失败,
std::identity行为确定、无歧义 - 示例对比:
std::vector<:string> v = {"zebra", "apple", "banana"}; // ✅ 清晰、高效、constexpr-safe std::ranges::sort(v, std::less{}, std::identity{}); // ⚠️ 手写 lambda 需额外注意引用类别 std::ranges::sort(v, std::less{}, [](auto&& x) -> decltype(auto) { return x; });</:string>
常见误用:把它当成“默认投影”自动启用
没有“默认投影”这回事。算法不会因为没传 projection 就悄悄用 std::identity;相反,不传 projection 时,算法走的是无投影重载(比如直接比较 *it),和传 std::identity{} 效果相同,但语义不同。
- 传
std::identity{}明确启用投影路径,影响 ADL 查找(比如可能找到自定义的operator 或投影友元) - 某些算法(如
std::ranges::unique)的投影版本与非投影版本行为一致,但类型约束不同:投影版要求indirectly_comparable<i i r proj></i>,而非投影版只要indirectly_comparable<i i r></i> - 调试时若看到
projection路径报错,别急着删掉std::identity{}—— 先确认是否真需要该重载,或是否漏了对应比较器的投影适配
真正容易被忽略的是:它只在 C++20 及以后可用,且需包含 <functional></functional>;如果项目还混用 C++17 工具链,自行定义一个空的 struct identity { template<class t> constexpr auto operator()(T&& t) const noexcept -> T&& { return static_cast<t>(t); } };</t></class> 是常见兜底做法,但要注意转发语义一致性。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










