什么向后兼容性需要为rvalues分配?

Ric*_*ick 13 c++

C++ Primer 5th:

(代码也来自书中,这里提供了99%的上下文)

#include <string>
using namespace std;
int main()
{
    //no error
    string s1 = "123", s2 = "aaaa";
    s1 + s2 = "wow";
    auto a = (s1 + s2).find("a");
}
Run Code Online (Sandbox Code Playgroud)

在新标准(这里是C++ 11)之前,没有办法阻止这种使用.为了保持向后兼容性,库类继续允许赋值给rvalues,但是,我们可能希望在我们自己的类中阻止这种用法.在这种情况下,我们想强制左手操作数(即this点的对象)为左值.

什么向后兼容性需要为rvalues分配?

顺便说一句,我也很好奇为什么s1 + s2 = "wow"被允许但int i = 3, j = 4; i + j = 7;不允许.(因为它密切相关,我选择不打开另一个问题)

luk*_*k32 2

这可能是一个反气候的猜测。我欢迎任何其他具体例子,但是遵循一般规则似乎非常合理。

  1. 这种限制不会破坏任何特定的代码,但会限制接受程序的范围。c++ 在进行此类更改时相当保守,有时会带来很大的痛苦。一个值得注意的例子是最令人烦恼的解析,如果A a();被解释为默认构造的代码会破坏什么A?然而,这种方式并不能向后兼容 c 语法。这是一个用于语法分析的 PIA。

  2. C++ 允许对用户定义类型的运算符含义进行语义重新定义。我不知道是否有语义重新定义的好例子,operator=其他运算符有一些相当值得注意的例子。 boost::program_optionsoperator()以一种相当奇怪的方式“滥用”,以创建简洁的语法,并且Eigen 重新定义了逗号运算符语义。指向成员的指针运算符经常被重新定义以执行非标准的操作,因为默认情况下不经常使用它们。所以有时候还是有用的。

  3. 我想它对于operator=有副作用的类可能很有用,并且不一定意味着改变内存中的值。我想在某些嵌入式开发中,您可以编写Row或编写类似的内容。我脑海中的另一个例子是表达式库,例如,还没有,所以可以在它的地方使用它来评估诸如.Colrow * col = LED_ONoperator<=>operator=(p ^ p) <=> p

operator=在运算符中没有什么特殊之处,并且它们实际上并不比其他成员函数更特殊。如果你写这样的代码:

#include <iostream>
using namespace std;

struct A{
friend ostream& operator<<(ostream& out, A& a) { out << "A "; return out;}
};    

int main() {
    A a1, a2;
    cout << a1=a2 << '\n';
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它会……破裂。这是因为按位移位优先=。它需要用括号括起来a1=a2。这是为了表明一个观点operator=语言确实没有特殊权利。

另一件事是您几乎可以按照您的意愿重载这些运算符,因此编写

#include <iostream>
using namespace std;

struct A{
    bool operator=(A& rhs) {return true;}
};    

int main() {
    A a1, a2;
    cout << (a1=a2) << '\n';
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

是完全合法的。语言为操作员提供了句法快捷方式,仅此而已。我认为很多人抱怨这(a+b).method()有效,这对于(a+b).operator=().

额外奖励:带有 s 的示例int不起作用,因为您无法重载基本类型的运算符,并且定义了默认运算符,因此它不接受右值。它表现出您似乎期望的行为。基本上我们被剥夺了重新定义原始类型运算符语义的自由。

  • “如果 A a(); 被解释为默认构造的 A,什么代码会中断?” 可能存在的每个 C++ 程序。 (3认同)