任何人都可以解释为什么这段代码编译:
typedef struct longlong
{
unsigned long low;
long high;
}
longlong;
typedef longlong Foo;
struct FooStruct
{
private:
Foo bar;
public:
void SetBar(Foo m)
{
bar = m;
}
Foo GetBar()
{
return bar;
}
};
int main()
{
FooStruct f;
Foo m1 = { 1,1 };
Foo m2 = { 2,2 };
f.SetBar(m1);
f.GetBar() = m2; // Here I'd expect an error such as
// "error: lvalue required as left operand of assignment"
}
Run Code Online (Sandbox Code Playgroud)
我预计编译失败的原因与error: lvalue required as left operand of assignment上线f.GetBar() = m2;,因为IMO f.GetBar()是不是一个左值,但它无缝地编译和f.GetBar() = m2;是NOP.
另一方面,如果我替换了typedef longlong Foo;by typedef long Foo;,前面提到的行将无法编译,我得到了预期的错误.
我在重构一些旧代码时遇到了这个问题.除了说明这个问题之外,这个问题中的代码没有其他目的.
Que*_*tin 12
这是有效的,因为它longlong是一个类,因此=是longlong::operator =隐式定义的赋值运算符.并且您可以在临时对象上调用成员函数,只要它们不合格&(默认operator =为不合格).
要将赋值运算符限制为左值,可以使用其他ref-qualifier显式地将其默认:
struct longlong
{
longlong &operator = (longlong const &) & = default;
// ^
// ...
};
Run Code Online (Sandbox Code Playgroud)
在类类型的对象上使用运算符意味着调用一个函数(左侧操作数的成员函数,或者将左侧操作数作为第一个参数的自由函数).这称为运算符重载.
在rvalues上调用函数是很好的,因此没有编译错误.
在实现重载赋值运算符时,您可以将其标记为不能在右值上调用它,但是您使用的任何类的设计者都选择不这样做.
Run Code Online (Sandbox Code Playgroud)f.GetBar() = m2; // Here I'd expect an error such as // "error: lvalue required as left operand of assignment"
你的期望是错误的.此规则仅适用于内置类型的对象.
[C++14: 3.10/5]:为了修改对象,对象的左值是必要的,除了在某些情况下也可以使用类类型的右值来修改它的指示对象.[示例:调用对象(9.3)的成员函数可以修改对象. - 末端的例子]
回想一下,你=的实际上是一个调用operator=,这是一个函数.
其他答案中描述了此行为的原因。
避免这种行为的一种方法是使用以下内容限定您的返回类型const:
struct FooStruct
{
...
const Foo GetBar() {return bar;}
};
Run Code Online (Sandbox Code Playgroud)
你不能给对象赋值const,所以编译器会抱怨。