# std::ranges::replace, std::ranges::replace_if

< cpp‎ | algorithm‎ | ranges

定义于头文件 `<algorithm>` |  |
调用签名 |  |
template< std::input_iterator I, std::sentinel_for<I> S, class T1, class T2, class Proj = std::identity > requires std::indirectly_writable<I, const T2&> && std::indirect_binary_predicate< ranges::equal_to, std::projected<I, Proj>, const T1*> constexpr I replace( I first, S last, const T1& old_value, const T2& new_value, Proj proj = {} ); | (1) | (C++20 起)
template< ranges::input_range R, class T1, class T2, class Proj = std::identity > requires std::indirectly_writable<ranges::iterator_t<R>, const T2&> && std::indirect_binary_predicate<ranges::equal_to, std::projected<ranges::iterator_t<R>, Proj>, const T1*> constexpr ranges::borrowed_iterator_t<R> replace( R&& r, const T1& old_value, const T2& new_value, Proj proj = {} ); | (2) | (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S, class T, class Proj = std::identity, std::indirect_unary_predicate< std::projected<I, Proj>> Pred > requires std::indirectly_writable<I, const T&> constexpr I replace_if( I first, S last, Pred pred, const T& new_value, Proj proj = {} ); | (3) | (C++20 起)
template< ranges::input_range R, class T, class Proj = std::identity, std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred > requires std::indirectly_writable<ranges::iterator_t<R>, const T&> constexpr ranges::borrowed_iterator_t<R> replace_if( R&& r, Pred pred, const T& new_value, Proj proj = {} ); | (4) | (C++20 起)

以 `new_value` 替换范围中 `[first, last)` 所有满足特定判别标准的元素。

1) 替换所有等于 `old_value` 的元素。用 std::invoke(proj, *i) == old_value 比较。
3) 替换所有谓词 `pred` 对其求值为 true 的元素，其中求值的表达式为 std::invoke(pred, std::invoke(proj, *i)) 。
2,4) 同 (1,3) ，但以 `r` 为范围，如同以 ranges::begin(r) 为 `first` 并以 ranges::end(r) 为 `last` 。

此页面上描述的仿函数实体是 niebloid ，即：

- 调用它们中的任何一者时不可指定显式模板实参。
- 它们无一对实参依赖查找可见。
- 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

### 参数

first, last | - | 要处理的元素范围
r | - | 要处理的元素范围
old_value | - | 要替换的元素的值
new_value | - | 要用作替换品的值
pred | - | 应用到投影后元素的谓词
proj | - | 应用到谓词的投影

### 返回值

等于 `last` 的迭代器。

### 复杂度

准确应用 ranges::distance(first, last) 次对应的谓词 `comp` 与任何投影 `proj` 。

### 注解

由于算法按引用接收 `old_value` 与 `new_value` ，它可能在任一参数为到范围 `[first, last)` 中元素的引用时有非期待的行为。

### 可能的实现

版本一
    struct replace_fn {
        template <std::input_iterator I, std::sentinel_for<I> S, class T1, class T2,
                 class Proj = std::identity>
        requires std::indirectly_writable<I, const T2&> && std::indirect_binary_predicate<
                  ranges::equal_to, std::projected<I, Proj>, const T1*>
        constexpr I
        operator() ( I first, S last, const T1& old_value, const T2& new_value,
                     Proj proj = {} ) const {
            for (; first != last; ++first) {
                if (old_value == std::invoke(proj, *first)) {
                    *first = new_value;
                }
            }
            return first;
        }

        template <ranges::input_range R, class T1, class T2, class Proj = std::identity>
        requires std::indirectly_writable<ranges::iterator_t<R>, const T2&> &&
                 std::indirect_binary_predicate<ranges::equal_to,
                 std::projected<ranges::iterator_t<R>, Proj>, const T1*>
        constexpr ranges::borrowed_iterator_t<R>
        operator() ( R&& r, const T1& old_value, const T2& new_value, Proj proj = {} ) const {
            return (*this)(ranges::begin(r), ranges::end(r), old_value,
                           new_value, std::move(proj));
        }
    };

    inline constexpr replace_fn replace{};
版本二
    struct replace_if_fn {
        template <std::input_iterator I, std::sentinel_for<I> S, class T,
                 class Proj = std::identity, std::indirect_unary_predicate<
                 std::projected<I, Proj>> Pred>
        requires std::indirectly_writable<I, const T&>
        constexpr I
        operator() ( I first, S last, Pred pred, const T& new_value, Proj proj = {} ) const {
            for (; first != last; ++first) {
                if (!!std::invoke(pred, std::invoke(proj, *first))) {
                    *first = new_value;
                }
            }
            return std::move(first);
        }

        template <ranges::input_range R, class T, class Proj = std::identity,
                 std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred>
        requires std::indirectly_writable<ranges::iterator_t<R>, const T&>
        constexpr ranges::borrowed_iterator_t<R>
        operator() ( R&& r, Pred pred, const T& new_value, Proj proj = {} ) const {
            return (*this)(ranges::begin(r), ranges::end(r), std::move(pred),
                           new_value, std::move(proj));
        }
    };

    inline constexpr replace_if_fn replace_if{};

### 示例

    #include <algorithm>
    #include <array>
    #include <iostream>

    int main()
    {
        auto print = [](const auto& v) {
            for (const auto& e : v) { std::cout << e << ' '; }
            std::cout << '\n';
        };

        std::array p{1, 6, 1, 6, 1, 6};
        print(p);
        std::ranges::replace(p, 6, 9);
        print(p);

        std::array q{1, 2, 3, 6, 7, 8, 4, 5};
        print(q);
        std::ranges::replace_if(q, [](int x){ return 5 < x; }, 5);
        print(q);
    }

输出：

    1 6 1 6 1 6
    1 9 1 9 1 9
    1 2 3 6 7 8 4 5
    1 2 3 5 5 5 4 5

### 参阅

ranges::replace_copy ranges::replace_copy_if (C++20)(C++20) | 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值 (niebloid)
replace replace_if | 将所有满足特定判别标准的值替换为另一个值 (函数模板)