Ежедневный бит(е) C++ #39, Косвенный обмен: std::iter_swap

std::iter_swap — это удобное сокращение для замены значений, на которые указывают два итератора.

В то время как исходная версия предназначена только для итераторов, версия диапазона C++20 может работать с любым косвенно перемещаемым типом и служит точкой настройки.

#include <vector>
#include <iterator>
#include <iostream>
#include <memory>
#include <ranges>

template <typename It, typename Sentinel>
requires std::bidirectional_iterator<It> &&
   std::sentinel_for<Sentinel,It>
void reverse(It begin, Sentinel end) {
    while (begin != end && std::next(begin) != end) {
        end = std::prev(end);
        // using iter_swap to swap the values behind the iterators
        std::iter_swap(begin,end);
        begin = std::next(begin);
    }
}

std::vector<int> data{1,2,3,4,5};
reverse(data.begin()+1, data.end()-1);
// data == { 1, 4, 3, 2, 5 }


// C++20 ranges
auto a = std::make_unique<int>(7);
auto b = std::make_unique<int>(42);
// Generalized iter_swap, works for any indirectly movable type.
std::ranges::iter_swap(a,b);
// *a == 42, *b == 7


// Customization point
struct Indirect {
    int* value_;
    friend void iter_swap(Indirect& l, Indirect& r) {
        std::cout << "Customization called.\n";
        int tmp = *l.value_;
        *l.value_ = *r.value_;
        *r.value_ = tmp;
    }
};

int x = 10, y = 20;
Indirect xi(&x), yi(&y);
// Calls customized iter_swap
std::ranges::iter_swap(xi,yi);
// x == 20, y == 10

Откройте этот пример в Compiler Explorer.