首页 > 解决方案 > 右值需要分配哪些向后兼容性?

问题描述

C++ 入门 5

(代码也来自本书,此处提供了 99% 的上下文)

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

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

右值需要分配哪些向后兼容性?

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

标签: c++

解决方案


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

  1. 这种限制不会破坏任何特定的代码,但会限制接受程序的域。当涉及到这样的变化时,c++ 是相当保守的,有时会非常痛苦。一个值得注意的例子是最令人烦恼的解析,如果A a();被解释为默认构造的代码会破坏什么A?然而,它不能以这种方式向后兼容 c 语法。那是一个相当用于语法分析的 PIA。

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

  3. 我想它可能对operator=具有副作用的类有用,并且不一定要更改内存中的值。我想在某些嵌入式开发中,您可以拥有Row并且Col您可以编写row * col = LED_ON或类似的东西。我脑海中的另一个例子是表达式库,例如,还没有operator<=>,所以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;
}

它会……破裂。那是因为按位移位优先=. 它需要在 . 周围加上括号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;
}

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

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


推荐阅读