为什么友元运算符要求其操作数具有常量性,而成员运算符则不需要?

Dan*_*a02 3 c++ compiler-errors

这可能与仅在某些情况下才允许引用临时对象有关,但我不确定此规则如何适用。

在这个例子中,编译器在 line 处停止,a + b + c因为a + b返回一个Int,为了计算 ,必须引用它(a+b) + c。根据我所读到的,这是一个深思熟虑的选择,因此临时值不会发生突变。修复此代码的方法是将签名更改为Int operator + (const Int & a, const int & b).

struct Int {
    int a;
    Int() { a = 0; }
    Int(int i) { a = i; }
    friend Int operator + (Int &, const Int &);
};

Int operator + (Int & a, const Int & b) {
    return Int(a.a + b.a);
}

int main() {
    Int a, b, c;
    a + b + c;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我们将运算符从friend函数更改为结构成员,那么这段代码应该与创建临时可变值具有相同的问题,实际上编译:

struct Int {
    int a;
    Int() { a = 0; }
    Int(int i) { a = i; }
    Int operator + (Int &);
};

Int Int::operator + (Int & v)
{
    return Int(a + v.a);
}

int main()
{
    Int a, b, c;
    a + b + c;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

为什么会发生这种情况?这两种情况看起来大多相同,但在后者中,不仅constRHS 值不需要 -ness,LHS 值也不需要。

Dan*_*ica 5

在第一种情况下,代码实际上等效于:

operator+(operator+(a, b), c);
Run Code Online (Sandbox Code Playgroud)

这里,表达式operator+(a, b)是一个rvalue,它不能绑定到非常量左值引用

在第二种情况下,我们有:

a.operator+(b).operator+(c);
Run Code Online (Sandbox Code Playgroud)

不存在这样的问题,因为只有左值 bc绑定到该非const左值参考参数。


正如@BenVoigt 指出的那样,您可能想知道在临时对象上调用非常量成员函数。这是完全合法的。标准中有关于它的特殊规则,@dfrib 的回答中有详细描述。