为什么可以有const赋值运算符

Bon*_*ero 13 c++ c++23

使用 C++23 将会有

std::pair<T1, T1>::operator =( const pair &other ) const;
Run Code Online (Sandbox Code Playgroud)

对我来说,对 const 对象进行赋值运算符没有任何意义,因为对象无法修改。为什么 C++23 在pair上有这个运算符?更令人困惑的是:

std::pair<T1, T1>::operator =( pair &&other ) const;
Run Code Online (Sandbox Code Playgroud)

[编辑]:这不起作用,因为 this 指向的内容将是 const:

template<typename T>
struct S
{
    void operator +=( T x ) const;
    T m_x;
};

template<typename T>
void S<T>::operator +=( T x ) const
{
    m_x += x;
}

int main( int argc, char **argv )
{
    S<int> si;
    si += 1;
}
Run Code Online (Sandbox Code Playgroud)

那么为什么会有一个带有pair的const限定赋值运算符呢?

Hol*_*Cat 11

这对于成对的非常量引用是有意义的。即使在 时,这些仍然是可分配的const。考虑:

#include <iostream>

template <typename T>
void foo(const T x) {x = 42;}

int main()
{
    int y = 1;
    foo<int &>(y);
    std::cout << y << '\n'; // 42
}
Run Code Online (Sandbox Code Playgroud)

但为什么还要费力支持它呢std::pair

我最近在某处看到了一个解释,但找不到链接(找到了)。它的大致思路是:

  • 您正在创建一个通用算法,并将结果分配给模板中的函数结果(例如分配给取消引用的迭代器)。如果函数碰巧按值返回,您可能会默默地得到意外行为(赋值不执行任何操作)。

  • 您希望出现编译错误,但实际上没有人 &限定其赋值运算符。

  • 那么合乎逻辑的下一步是检查返回类型并拒绝非引用。

  • 但你想留下一个漏洞。例如,取消引用std::vector<bool>迭代器按值返回(代理对象),并且应该允许对其进行赋值。

  • 你可以为它发明一种类型特征,但还有一个聪明的选择。const如果添加到返回类型,则检查赋值是否仍然可以编译。如果没有,则会引发编译错误。这很好地概括为返回引用,因为添加const到它们会使类型保持不变(如果引用是非常量,则仍然可以分配)。

  • 为了使其工作,您需要添加const所有此类类型的赋值运算符(这是为 完成的std::vector<bool>::reference)。

  • 至于为什么std::pair(和std::tuple)需要它:从std::views::zip()取消引用到引用元组的迭代器,并且您希望能够分配给这些元组。

但我不记得 C++23 中哪些标准算法会受到这样的约束。可能是某个范围内的东西...