Реализация std::swap
может выглядеть так:
template <class T> void swap (T& a, T& b)
{
T c(std::move(a)); a=std::move(b); b=std::move(c);
}
template <class T, size_t N> void swap (T (&a)[N], T (&b)[N])
{
for (size_t i = 0; i<N; ++i) swap (a[i],b[i]);
}
Реализация std::exchange
n3668 может выглядеть так:
template< typename T, typename U = T >
T exchange( T & obj, U && new_val )
{
T old_val = std::move(obj);
obj = std::forward<U>(new_val);
return old_val;
}
В нем говорится:
Для примитивных типов это эквивалентно очевидной реализации, а для более сложных типов это определение
- Предотвращает копирование старого значения, когда этот тип определяет конструктор перемещения
- Принимает любой тип в качестве нового значения, используя любой оператор присваивания преобразования
- Предотвращает копирование нового значения, если оно временно или перемещено.
Я выбрал имя для симметрии с atomic_exchange, так как они ведут себя то же самое, за исключением того, что эта функция не является атомарной.
n3746 также предлагает встроенный оператор свопинга, который выглядит следующим образом:
inline C& C::operator :=: (C&& y) & { see below; return *this; }
inline C& C::operator :=: (C& y) & { return *this :=: std::move(y); }
Из того, что я собираю, предложения хотели бы, чтобы все три из этих вариантов жили бок о бок, а не заменяли друг друга. Почему необходимо иметь три разных способа обмена объектами?