# std::ranges::swap_ranges, std::ranges::swap_ranges_result

< cpp‎ | algorithm‎ | ranges

定义于头文件 `<algorithm>` |  |
调用签名 |  |
template< std::input_iterator I1, std::sentinel_for<I1> S1, std::input_iterator I2, std::sentinel_for<I2> S2 > requires std::indirectly_swappable<I1, I2> constexpr swap_ranges_result<I1, I2> swap_ranges( I1 first1, S1 last1, I2 first2, S2 last2 ); | (1) | (C++20 起)
template< ranges::input_range R1, ranges::input_range R2 > requires std::indirectly_swappable<ranges::iterator_t<R1>, ranges::iterator_t<R2>> constexpr swap_ranges_result<ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>> swap_ranges( R1&& r1, R2&& r2 ); | (2) | (C++20 起)
辅助类型 |  |
template< class I1, class I2 > using swap_ranges_result = ranges::in_in_result<I1, I2>; | (3) | (C++20 起)

1) 在第一范围 `[first1, first1 + M)` 与第二范围 `[first2, first2 + M)` 间交换元素，其中 M = ranges::min(ranges::distance(first1, last1), ranges::distance(first2, last2)) 。
范围 `[first1, last1)` 与 `[first2, last2)` 必须不重叠。
2) 同 (1) ，但以 `r1` 为第一范围并以 `r2` 为第二范围，如同以 ranges::begin(r1) 为 `first1` ，以 ranges::end(r1) 为 `last1` ，以 ranges::begin(r2) 为 `first2` ，并以 ranges::end(r2) 为 `last2` 。

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

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

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

### 参数

first1, last1 | - | 要交换的第一范围
first2, last2 | - | 要交换的第二范围
r1 | - | 要交换的第一范围
r2 | - | 要交换的第二范围

### 返回值

1{first1 + M, first2 + M} 。

### 复杂度

准确交换 M 次。

### 注解

实现（例如 MSVC STL ）可能在迭代器类型实现 `contiguous_iterator` ，并且交换其值类型不调用非平凡的特殊成员函数或 ADL 所找到的 `swap` 时启用向量化。

### 可能的实现

    struct swap_ranges_fn {

      template<std::input_iterator I1, std::sentinel_for<I1> S1,
               std::input_iterator I2, std::sentinel_for<I2> S2>
        requires std::indirectly_swappable<I1, I2>
          constexpr ranges::swap_ranges_result<I1, I2>
            operator() ( I1 first1, S1 last1, I2 first2, S2 last2 ) const {
                for (; !(first1 == last1 or first2 == last2); ++first1, ++first2)
                    ranges::iter_swap(first1, first2);
                return {std::move(first1), std::move(first2)};
            }

      template<ranges::input_range R1, ranges::input_range R2>
        requires std::indirectly_swappable<ranges::iterator_t<R1>, ranges::iterator_t<R2>>
          constexpr ranges::swap_ranges_result<ranges::borrowed_iterator_t<R1>,
                                               ranges::borrowed_iterator_t<R2>>
            operator() ( R1&& r1, R2&& r2 ) const {
                return (*this)(ranges::begin(r1), ranges::end(r1),
                               ranges::begin(r2), ranges::end(r2));
            }
    };

    inline constexpr swap_ranges_fn swap_ranges{};

### 示例

    #include <algorithm>
    #include <iostream>
    #include <list>
    #include <string_view>
    #include <vector>

    auto print(std::string_view name, auto const& seq, std::string_view term = "\n") {
        std::cout << name << " : ";
        for (const auto& elem : seq)
            std::cout << elem << ' ';
        std::cout << term;
    }

    int main()
    {
        std::vector<char>  p {'A', 'B', 'C', 'D', 'E'};
        std::list<char>    q {'1', '2', '3', '4', '5', '6'};

        print("p", p);
        print("q", q, "\n\n");

        // 交换 p[0, 2) 与 q[1, 3):
        std::ranges::swap_ranges(p.begin(),
                                 p.begin() + 4,
                                 std::ranges::next(q.begin(), 1),
                                 std::ranges::next(q.begin(), 3));
        print("p", p);
        print("q", q, "\n\n");

        // 交换 p[0, 5) 与 q[0, 5):
        std::ranges::swap_ranges(p, q);

        print("p", p);
        print("q", q);
    }

输出：

    p : A B C D E
    q : 1 2 3 4 5 6

    p : 2 3 C D E
    q : 1 A B 4 5 6

    p : 1 A B 4 5
    q : 2 3 C D E 6

### 参阅

iter_swap (C++20) | 交换两个可解引用对象所引用的值 (定制点对象)
ranges::swap (C++20) | 交换两个对象的值 (定制点对象)
swap_ranges | 交换两个范围的元素 (函数模板)
iter_swap | 交换两个迭代器所指向的元素 (函数模板)
swap | 交换两个对象的值 (函数模板)