函数返回struct为LValue

bgp*_*000 24 c++ gcc

在下面的代码片段中,为什么行o.margin() = m;编译没有错误?它很容易引起警告,因为它几乎总是一个错误.我实际上认为它是一个错误,因为它在赋值的左侧放置了一个R值.

#include <iostream>

struct Margin
{
    Margin(int val=0) : val(val) {};
    int val;
};

struct Option
{
    Margin m;
    int z=0;

    Margin margin()const { return m; }
    int zoomLevel() { return z; }
};


int main()
{
    Option o;
    std::cout << "Margin is: "<< o.margin().val << std::endl;

    Margin m = { 3 };

    // The following line is a no-op, which generates no warning:
    o.margin() = m;

    // The following line is an error
    // GCC 4.9.0: error: lvalue required as left operand of assignment
    // clang 3.8: error: expression is not assignable
    // MSVC 2015: error C2106: '=': left operand must be l-value
     o.zoomLevel() = 2;

    std::cout << "Margin is: "<< o.margin().val << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

Margin is: 0
Margin is: 0
Run Code Online (Sandbox Code Playgroud)

mar*_*inj 14

您可以修改类类型的返回类型(通过调用非const方法):

3.10/5来自n4140

5为了修改对象,对象的左值是必要的,除了在某些情况下也可以使用类类型的右值来修改它的指示对象.[示例:调用对象(9.3)的成员函数可以修改对象. - 末端的例子]

你的代码:

o.margin() = m;
Run Code Online (Sandbox Code Playgroud)

实际上是一样的

o.margin().operator=( Margin(m) );
Run Code Online (Sandbox Code Playgroud)

因此,如果将其更改为:const const方法,则调用它:

o.margin().val = m;
Run Code Online (Sandbox Code Playgroud)

然后你会得到一个错误.

另一方面,这里:

o.zoomLevel()= 2;

zoomLevel() 返回非类类型,因此您无法修改它.

  • 我从不怀疑可以在rvalue上调用成员函数.我以前从未想过它可以与赋值运算符一起使用.你知道使用赋值运算符的习语吗? (2认同)

Bo *_*son 10

何时o是类类型的对象,operator=是成员函数.代码 o.margin() = m;相当于o.margin().operator=(m);.

您可以调用临时类对象的成员函数,类似于访问成员的方式o.margin().val.

此外,类的赋值运算符可以被覆盖,而根本不是无操作符.