# std::ranges::replace_copy, std::ranges::replace_copy_if, std::ranges::replace_copy_result, std::ranges::replace_copy_if_result

< cpp‎ | algorithm‎ | ranges

定义于头文件 `<algorithm>` |  |
调用签名 |  |
template< std::input_iterator I, std::sentinel_for<I> S, class T1, class T2, std::output_iterator<const T2&> O, class Proj = std::identity > requires std::indirectly_copyable<I, O> && std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>, const T1*> constexpr replace_copy_result<I, O> replace_copy( I first, S last, O result, const T1& old_value, const T2& new_value, Proj proj = {} ); | (1) | (C++20 起)
template< ranges::input_range R, class T1, class T2, std::output_iterator<const T2&> O, class Proj = std::identity > requires std::indirectly_copyable<ranges::iterator_t<R>, O> && std::indirect_binary_predicate<ranges::equal_to, std::projected<ranges::iterator_t<R>, Proj>, const T1*> constexpr replace_copy_result<ranges::borrowed_iterator_t<R>, O> replace_copy( R&& r, O result, 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, std::output_iterator<const T&> O, class Proj = std::identity, std::indirect_unary_predicate< std::projected<I, Proj>> Pred > requires std::indirectly_copyable<I, O> constexpr replace_copy_if_result<I, O> replace_copy_if( I first, S last, O result, Pred pred, const T& new_value, Proj proj = {} ); | (3) | (C++20 起)
template< ranges::input_range R, class T, std::output_iterator<const T&> O, class Proj = std::identity, std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred > requires std::indirectly_copyable<ranges::iterator_t<R>, O> constexpr replace_copy_if_result<ranges::borrowed_iterator_t<R>, O> replace_copy_if( R&& r, O result, Pred pred, const T& new_value, Proj proj = {} ); | (4) | (C++20 起)
辅助类型 |  |
template< class I, class O > using replace_copy_result = ranges::in_out_result<I, O>; | (5) | (C++20 起)
template< class I, class O > using replace_copy_if_result = ranges::in_out_result<I, O>; | (6) | (C++20 起)

从源范围 `[first, last)` 复制元素到始于 `result` 的目标范围，以 `new_value` 替换所欲满足特定标准的元素。若源范围与目标范围重叠则行为未定义。

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

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

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

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

### 参数

first, last | - | 要复制的元素范围
r | - | 要复制的元素范围
result | - | 目标范围的起始
old_value | - | 要替换的元素的值
new_value | - | 用作替换品的值
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

### 返回值

{last, result + N} ，其中

1,3) N = ranges::distance(first, last) ；
2,4) N = ranges::distance(r) 。

### 复杂度

准确应用 N 次对应的谓词 `comp` 与投影 `proj` 。

### 可能的实现

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

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

    inline constexpr replace_copy_fn replace_copy{};
版本二
    struct replace_copy_if_fn {
        template <std::input_iterator I, std::sentinel_for<I> S, class T,
                 std::output_iterator<const T&> O,
                 class Proj = std::identity, std::indirect_unary_predicate<
                 std::projected<I, Proj>> Pred>
        requires std::indirectly_copyable<I, O>
        constexpr ranges::replace_copy_if_result<I, O>
        operator()( I first, S last, O result, Pred pred, const T& new_value,
                    Proj proj = {} ) const {
            for (; first != last; ++first, ++result) {
                 *result = std::invoke(pred, std::invoke(proj, *first)) ? new_value : *first;
            }
            return {std::move(first), std::move(result)};
        }

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

    inline constexpr replace_copy_if_fn replace_copy_if{};

### 示例

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

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

        std::vector<int> o;

        std::array p{1, 6, 1, 6, 1, 6};
        o.resize(p.size());
        print("p", p);
        std::ranges::replace_copy(p, o.begin(), 6, 9);
        print("o", o);

        std::array q{1, 2, 3, 6, 7, 8, 4, 5};
        o.resize(q.size());
        print("q", q);
        std::ranges::replace_copy_if(q, o.begin(), [](int x){ return 5 < x; }, 5);
        print("o", o);
    }

输出：

    p: 1 6 1 6 1 6
    o: 1 9 1 9 1 9
    q: 1 2 3 6 7 8 4 5
    o: 1 2 3 5 5 5 4 5

### 参阅

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