我应该为赋值运算符使用左值引用限定符吗
Should I use lvalue reference qualifiers for assignment operators?
最近,我关注了一个关于C++中表达式赋值的讨论,如下例所示:
string s1, s2, s3;
(s1 + s2) = s3;
使用C++11,可以将赋值运算符限制为左值引用(在左侧)。当如下声明赋值运算符时,编译器Clang会由于不兼容的类型而拒绝带有错误消息的代码。
auto operator=(const string& rhs) & -> string&;
auto operator=(string&& rhs) & -> string&;
我哪儿也没见过。是否有充分的理由不使用赋值运算符的左值引用限定符(除了在大多数编译器中缺少支持之外)?
有趣!我甚至没有意识到这一点,花了一段时间才找到它(这是"将移动语义扩展到*this"提案的一部分)。8.3.5[dcl.dell]第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));
}
这可能是滥用赋值运算符从右值中获取左值,但这不太可能偶然发生。因此,我不会特意通过限制赋值运算符仅适用于lvalues来实现这一点。当然,将赋值中的右值返回到右值也可以防止这种情况。这两种用途中哪一种更有用(如果有的话)可能是一个考虑因素。
顺便说一句,clang似乎支持您从2.9版本开始引用的语法。
除了在大多数编译器中缺少支持之外,是否有充分的理由不使用赋值运算符的左值引用限定符?
不,不是真的。使用左值或右值限定符为左值或右值对象构造正确的接口与使用const
相同,并且应该以相同的方式处理它-每个函数都应该考虑限制。给右值赋值实际上没有意义,所以应该禁止它。
你没有看到它的原因主要是编译器支持不力——*this
的右值引用有点像thread_local
,大多数编译器实现者似乎都把它放在了"从C++11实现的功能"堆栈的底部。
我对你的建议不太感兴趣的一个原因是,我试图回避宣布特殊成员。因此,我的大多数赋值运算符都是隐式声明的,因此没有ref限定符。
当然,当我写一个类或类模板来管理所有权时(见上面链接中的结论),我可以注意只为lvalues声明这些运算符。然而,由于它对客户没有影响,所以没有什么意义。
- 标准库类型的赋值运算符的引用限定符
- 移动赋值运算符;尝试引用已删除的函数.我该如何解决这个问题?
- 为什么我需要三个嵌套的大括号来调用赋值运算符,将const引用到二维数组
- 如果类在 C++ 中具有常量或引用类型的非静态数据成员,为什么编译器不提供默认赋值运算符?
- 为什么类的赋值运算符的返回类型通常是非常量(而不是常量)引用?
- 引用模板类型的赋值运算符需要非常量重载
- 为什么在取消引用的指向接口的指针上使用赋值运算符不是编译器错误
- 如何为具有自引用指针的类实现复制构造函数/赋值运算符
- 尽管返回了引用,但无法链接重载的赋值运算符
- 错误:非静态引用成员"std::ostream&Student::out",无法使用默认赋值运算符
- 我应该为赋值运算符使用左值引用限定符吗
- 错误:非静态引用成员,无法使用默认赋值运算符
- 带有右值引用参数的模板赋值运算符与 vs2013 和 gcc 的行为不同
- 如果类具有引用数据成员,为什么编译器不合成默认赋值运算符
- 为什么在赋值运算符重载中返回引用
- 为什么引用类型成员会导致删除隐式声明的复制赋值运算符
- 类成员作为对另一个的引用:赋值运算符中的崩溃
- 使用值而不是引用的赋值运算符的分支
- 带有赋值运算符的右值引用
- 处理赋值运算符重载;您可以重新分配引用吗?