std::identity (在 C++20 中引入)是一个函数对象,其 operator() 返回其参数不变。
注释
<utility>中有一个特定于Microsoft的 identity 结构,该结构已弃用,在更高版本的 Visual Studio 中不可用。 对于 C++20 及更高版本,请 std::identity 改用 <functional> ,这是下面所述的符合标准的等效项。
std::identity (C++20)
许多标准库 API 采用可调用的参数,例如投影或转换函数。 如果需要传递可调用但不想更改数据,请传递 std::identity。 这在范围算法中很常见。 许多 <algorithm> 范围重载都有一个默认为 std::identity{}的投影参数。
语法
struct identity
{
template <class T>
_NODISCARD constexpr T&& operator()(T&& t) const noexcept;
using is_transparent = int;
};
注解
成员 is_transparent 类型是标记为透明函数对象的标记 std::identity 。 其存在表明算法可以执行比较或投影,而无需先将类型转换为通用形式。 这对于支持异类查找的关联容器和算法非常有用,允许它们直接比较不同类型的,而无需构造临时对象。
示例
#include <algorithm>
#include <functional>
#include <iostream>
#include <ranges>
#include <vector>
int main()
{
std::vector<int> v{3, 1, 4, 1, 5, 9, 2, 6};
// Ranges algorithms can apply a projection before comparison.
// But if you don't want to apply a projection, i.e. you don't want to modify the data
// before comparison, you can use std::identity to leave each element unchanged.
// Here, std::identity{} means "project each element as itself".
// So the comparator sees the original int values unchanged.
std::ranges::sort(v, std::less{}, std::identity{});
// This call is equivalent because std::identity{} is the default projection.
// In both calls, elements are sorted directly; no field extraction or
// value transformation happens first.
std::ranges::sort(v);
for (int n : v)
{
std::cout << n << ' ';
}
std::cout << '\n';
// Output: 1 1 2 3 4 5 6 9
}
此示例使用std::string_view键搜索std::vector<std::string>。 由于 std::identity 具有 is_transparent 成员,因此算法知道直接比较这些类型。 这样,密钥就不会转换为临时 std::string 密钥,只是为了进行比较。
#include <algorithm>
#include <functional>
#include <iostream>
#include <ranges>
#include <string>
#include <string_view>
#include <vector>
int main()
{
std::vector<std::string> words{"apple", "banana", "cherry", "date"};
std::string_view key = "cherry";
// `std::less<>` is transparent, so it can compare `std::string` and
// `std::string_view` directly.
// `std::identity` is also marked transparent (`is_transparent`), so the
// projection stays type-flexible instead of forcing one fixed type.
auto it = std::ranges::lower_bound(words, key, std::less<>{}, std::identity{});
if (it != words.end() && *it == key)
{
std::cout << "Found: " << *it << '\n';
}
}