CodeNebula
C++20stladvanced

std::identity (C++20 Addition)

C++20 · The Big Four · Compiler flag: -std=c++20

Explanation

A transparent function object that returns its argument unchanged. Serves as the default projection for range algorithms, enabling clean default parameter values.

Real-World Scenario

Use as a default no-op projection when writing a generic algorithm that optionally projects elements.

Quick Snippet

snippet.cpp
#include <functional>
#include <algorithm>
#include <ranges>
#include <vector>

template<std::ranges::range R, typename Proj = std::identity>
void print_sorted(R&& r, Proj proj = {}) {
    std::vector<std::ranges::range_value_t<R>> copy(std::ranges::begin(r), std::ranges::end(r));
    std::ranges::sort(copy, {}, proj);
}

Full Example

identity.cpp
// CodeNebula - C++20 Example: std::identity
// Compile: g++ -std=c++20 -Wall -Wextra -o example identity.cpp

#include <functional>
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>

int main() {
    // std::identity returns its argument unchanged
    std::identity id;
    std::cout << "identity(42):      " << id(42) << '\n';
    std::cout << "identity(3.14):    " << id(3.14) << '\n';
    std::cout << "identity(\"hello\"): " << id(std::string("hello")) << '\n';

    // Primary use: default projection in ranges algorithms
    std::vector<int> nums = {5, 3, 8, 1, 9, 2, 7};
    std::ranges::sort(nums, std::less<>{}, std::identity{});
    std::cout << "\nSorted: ";
    for (int n : nums) std::cout << n << ' ';
    std::cout << '\n';

    // Useful in generic/template code as a default projection
    auto find_max = [](auto& range, auto proj = std::identity{}) {
        return *std::ranges::max_element(range, {}, proj);
    };

    std::vector<int> values = {10, 40, 20, 50, 30};
    std::cout << "\nMax value: " << find_max(values) << '\n';

    // Same function with a custom projection
    struct Item {
        std::string name;
        double price;
    };
    std::vector<Item> items = {
        {"Widget", 9.99}, {"Gadget", 24.99},
        {"Gizmo", 14.99}, {"Doohickey", 4.99}
    };

    auto expensive = find_max(items, &Item::price);
    std::cout << "Most expensive: " << expensive.name
              << " ($" << expensive.price << ")\n";

    // identity in generic wrappers that optionally transform values
    auto apply_and_print = [](const auto& range, auto transform = std::identity{}) {
        for (const auto& elem : range)
            std::cout << transform(elem) << ' ';
        std::cout << '\n';
    };

    std::vector<int> data = {1, 2, 3, 4, 5};
    std::cout << "\nWith identity:  ";
    apply_and_print(data);
    std::cout << "With transform: ";
    apply_and_print(data, [](int x) { return x * x; });

    // Use with std::transform as a copy operation
    std::vector<int> src = {10, 20, 30};
    std::vector<int> dst(3);
    std::ranges::transform(src, dst.begin(), std::identity{});
    std::cout << "\nCopied via identity: ";
    for (int d : dst) std::cout << d << ' ';
    std::cout << '\n';

    return 0;
}
Run command
g++ -std=c++20 -Wall -Wextra -o example identity.cpp