identity 結構

std::identity (在 C++20 中引入)是一個函式物件,其 operator() 參數不變。

備註

<utility> 有一個專屬於 Microsoft 的 identity 結構,但已經被棄用,且在後續版本的 Visual Studio 中無法使用。 對於 C++20 及以後版本,請使用 std::identity from <functional> instead 作為下文標準相容的等效工具。

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為透明函式物件的標籤。 其存在表示演算法能在不先將型別轉換為通用形式的情況下進行比較或投影。 這對於關聯容器和支援異質查找的演算法非常有用,能直接比較不同類型,無需建構臨時物件。

Examples

#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鍵搜尋 astd::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';
    }
}