10

使用 C++23 将有

std::pair<T1, T1>::operator =( const pair &other ) const;

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

std::pair<T1, T1>::operator =( pair &&other ) const;

[编辑]:这行不通,因为 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;
}

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

4

1 回答 1

8

对于非常量引用对是有意义的。即使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
}

但是为什么还要支持它std::pair呢?

我最近在 SO 的某个地方看到了一个解释,但找不到链接(找到它)。它遵循以下路线:

  • 您正在制作一个通用算法,并且您正在分配给模板中的函数结果(例如取消引用的迭代器)。如果函数碰巧按值返回,您可能会默默地得到意想不到的行为(赋值什么都不做)。

  • 您想要一个编译错误,但实际上没有人 &- 限定他们的赋值运算符。

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

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

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

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

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

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

于 2022-02-12T11:10:33.337 回答