const swap() 函数的目的是什么?

What's the purpose of const swap() function?

在实施自定义 tuple (here), I found there is a wired swap() function that takes const parameters (cppreference) 时:

template< class... Types >
constexpr void swap( const std::tuple<Types...>& lhs,
                     const std::tuple<Types...>& rhs ) noexcept(/* see below */);

和一个 const 限定的 swap() 成员函数 (cppreference):

constexpr void swap( const tuple& other ) noexcept(/* see below */) const;

const表示该对象是只读的,但是要交换两个对象,它必须修改对象,这违反了const-ness。

那么,const swap() 函数的目的是什么?

您错过了有关重载何时可用的脚注:

This overload participates in overload resolution only if std::is_swappable_v<const Ti> is true for all i from 0 to sizeof...(Types).

如果您的类型 const_swappable 使得 swap(const const_swappable &, const const_swappable &) 合理,那么您没有理由不能交换 const std::tuple<const_swappable> &.

例如,考虑一个 pointer-like 类型,它可以在不修改指针的情况下交换指针对象的值:

#include <type_traits>
#include <iostream>

struct foo {
    int * x;
};

void swap(const foo& a, const foo& b){
    std::swap(*a.x,*b.x);
};

int main(){
    int a = 42;
    int b = 3;

    foo f1{&a};
    foo f2{&b};

    swap(f1,f2);

    std::cout << "foo is const swappable: " << std::is_swappable_v<const foo> << "\n";
    std::cout << *f1.x << "\n";
    std::cout << *f2.x << "\n";

}

来自 cppreference 的注释:

  1. The program is ill-formed if (std::is_swappable_v<const Types> && ...) is not true.

即:如果元组中的类型可以常量交换,则只能常量交换元组。

这是在“zip”提案中引入的 P2321 originally described in "A Plan for C++23 Ranges" P2214

P2321

  • swap for const tuple and const pair. Once tuples of references are made const-assignable, the default std::swap can be called for const tuples of references. However, that triple-move swap does the wrong thing:

    int i = 1, j = 2;
    const auto t1 = std::tie(i), t2 = std::tie(j);
    
    // If std::swap(t1, t2); called the default triple-move std::swap then
    // this would do
    auto tmp = std::move(t1);
    t1 = std::move(t2);
    t2 = std::move(tmp);
    
    // i == 2, j == 2
    

    This paper therefore proposes adding overloads of swap for const tuples and pairs to correctly perform element-wise swap.

P2214 解释了为什么 zip 的实现需要 const 可分配性。它源于赋值运算符没有被 ref 限定。