16

最近,我关注了关于 C++ 中表达式赋值的讨论,如下例所示:

string s1, s2, s3;
(s1 + s2) = s3;

使用 C++11,可以将赋值运算符限制为左值引用(在左侧)。当如下声明赋值运算符时,编译器 Clang 由于类型不兼容而拒绝代码并显示错误消息。

auto operator=(const string& rhs) & -> string&;
auto operator=(string&& rhs) & -> string&;

我在任何地方都没有看到这个。是否有充分的理由不为赋值运算符使用左值引用限定符(除了在大多数编译器中缺少支持)?

4

3 回答 3

8

有趣的!我什至没有意识到这一点,花了我一段时间才找到它(这是“将移动语义扩展到 *this”提案的一部分)。该符号在 8.3.5 [dcl.decl] 第 4 段中定义,以防有人想查看。

无论如何:现在,了解此功能似乎最有用的是使用它进行重载,并且如果调用函数的对象是左值或右值,则可能表现不同。用它来限制可以做什么,例如,赋值的结果似乎没有必要,特别是如果对象实际上是一个左值。例如,您可能希望语法从分配给一个右值返回一个右值:

struct T {
    auto operator=(T&) & -> T&;
    auto operator=(T&&) & -> T&;
    auto operator=(T&) && -> T;
    auto operator=(T&&) && -> T;
};

这里的目的是允许从分配结果中移动(尽管这是否值得,但我不确定:为什么不首先跳过分配?)。我认为我不会主要使用此功能来限制使用。

就个人而言,我喜欢有时从右值中获取左值的可能性,而赋值运算符通常是实现此目的的一种方式。例如,如果您需要将一个左值传递给一个函数,但您知道您不想对它使用任何东西,您可以使用赋值运算符获取一个左值:

#include <vector>
void f(std::vector<int>&);
int main()
{
    f(std::vector<int>() = std::vector<int>(10));
}

这可能是对赋值运算符从右值获取左值的滥用,但这不太可能是偶然发生的。因此,我不会特意通过将赋值运算符限制为仅适用于左值来使这成为不可能。当然,从赋值中返回一个右值也可以防止这种情况发生。如果有的话,这两种用途中哪一种更有用,可能是一个考虑因素。

顺便说一句,clang 似乎支持您从 2.9 版开始引用的语法。

于 2012-10-06T12:50:26.310 回答
4

是否有充分的理由不为赋值运算符使用左值引用限定符(除了在大多数编译器中缺少支持)?

不,不是。使用 lvalue 或 rvalue 限定符为 lvalue 或 rvalue 对象构造正确的接口与使用 相同const,并且应该以相同的方式处理 - 每个函数都应考虑限制。分配给右值实际上没有意义,因此应该禁止。

您没有看到它的原因主要是编译器支持不佳 - rvalue refs*this有点像thread_local,大多数编译器实现者似乎已经将它放在“从 C++11 实现的功能”堆栈的底部附近。

于 2012-10-06T12:54:56.413 回答
4

我对你的建议不是超级热心的一个原因是我试图完全避免宣布特殊成员。因此,我的大多数赋值运算符都是隐式声明的,因此没有引用限定符。

Of course, for those times when I do write a class or class template to e.g. manage ownership (see conclusion in above link), I could take care to declare those operators for lvalues only. Since it has no effects on clients however, there isn't much of a point.

于 2012-10-06T14:11:16.767 回答