std::identity 是 c++20 引入的标准库空操作函数对象,定义于 ,作用是原样返回参数;其类型为无状态、const 且 noexcept 的类,支持完美转发,适用于投影、泛型占位等场景。

std::identity 是个啥函数对象
它是个标准库提供的空操作函数对象,作用就是原样返回传入的参数,不改变、不计算、不判断。C++20 引入,定义在 <functional></functional> 头文件里。
常见错误现象:写 std::identity() 却编译失败——忘了 C++ 标准版本必须 ≥20,GCC/Clang 需加 -std=c++20;MSVC 19.30+ 才支持。
- 它不是模板别名或类型推导辅助,而是一个具体的类类型:
std::identity(注意没括号) - 实例化后是可调用对象,比如
std::identity{}(x)等价于直接写x - 和手写
[](auto&& x) { return x; }行为一致,但更轻量、无捕获、有标准语义保证
什么时候非得用 std::identity
主要出现在泛型算法需要“透传”参数、又不能写死类型或值的场景,尤其是配合 std::ranges::transform、std::ranges::sort 或 std::ranges::max_element 这类接受投影(projection)参数的函数。
使用场景举例:对结构体数组按某个字段排序,但字段名本身是运行时无关的——这时用 std::identity{} 作为投影,表示“就用元素本身比较”,避免手写 lambda 引入额外开销或生命周期问题。
立即学习“C++免费学习笔记(深入)”;
行盟APP是结合了通信和互联网的优势,加之云计算所拥有的强大信息资源,借助广大的终端传递服务,潜在的拥有巨大商机。她到底是什么,又有什么作用?她是一款手机应用软件;她是一款专门为企业服务的手机应用软件;她是一款能够将企业各种信息放入其中并进行推广传播的手机应用软件!只要轻轻一点,企业的简介,产品信息以及其他优势就能最快最大限度的透过手机展现在客户的眼前,一部手机,一个APP,你面对的将是一个6亿&
-
std::ranges::sort(vec, {}, std::identity{}):等价于默认升序,但显式声明“不投影”,语义更清晰 - 配合
std::views::transform做类型擦除过渡:vec | std::views::transform(std::identity{})不改变值,但可能触发 view 的惰性求值优化 - 模板元编程中作占位符:比如某算法模板参数要求一个可调用对象,你暂时不想做任何转换,
std::identity比自定义 struct 更标准、更易读
std::identity 和手写 lambda 有啥区别
核心差异在类型唯一性、内联行为和 SFINAE 友好度上。编译器对 std::identity 有特殊认知,某些上下文能更好优化或推导。
性能影响:绝大多数情况下无差别;但某些老编译器对 lambda 捕获空结构体仍可能生成虚表或额外符号,而 std::identity 是无状态、无成员变量的 trivial 类型,sizeof 为 1 且 guaranteed copy elision。
- lambda 类型每次出现都不同,无法跨函数签名复用;
std::identity类型固定,适合做模板参数约束(如requires std::regular_invocable<:identity int></:identity>) - 兼容性风险:C++17 项目不能用;若误写成
std::identity()(带括号),会触发函数声明解析(most vexing parse),变成函数声明而非对象构造 - 调试时更友好:
std::identity{}在 gdb/lldb 中显示明确,而匿名 lambda 名字是编译器生成的乱码
容易被忽略的细节
std::identity 的 operator() 是 const-qualified 且 noexcept,返回类型严格匹配参数类型(保留引用、cv 限定符),这点比很多手写通用 lambda 更严谨。
比如传入 const std::string&,std::identity{}(s) 返回的仍是 const std::string&;而 [](auto&& x) { return x; } 在某些编译器下可能退化为值返回,引发意外拷贝。
- 它不接受多个参数:只有单参数重载,没有
operator()(T, U),别试图拿来当二元函数用 - 不能用于需要 mutable 语义的场景——它天生 immutable,连
mutable关键字都加不上 - 头文件漏掉
<functional></functional>时,部分编译器报错信息极不友好,可能只提示“no type named ‘identity’ in namespace ‘std’”,而不是直接说“未包含头文件”









