函数返回struct为LValue

时间:2016-05-31 11:33:56

标签: 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;
}

输出:

Margin is: 0
Margin is: 0

4 个答案:

答案 0 :(得分:14)

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

3.10 / 5,来自n4140

  

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

您的代码:

o.margin() = m;

实际上与

相同
o.margin().operator=( Margin(m) );

如果将其更改为:

,则调用非const方法
o.margin().val = m;

然后你会收到错误。

另一方面:

o.zoomLevel()= 2;

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

答案 1 :(得分:10)

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

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

此外,类的赋值运算符可以被覆盖,而不是完全无操作。

答案 2 :(得分:4)

如果您想禁止此类用途,那么从C ++ 11开始,您可以在赋值运算符上使用reference qualifier

Margin& operator=(const Margin&) & = default;

这将在GCC 5.1上生成以下错误:

error: passing 'Margin' as 'this' argument discards qualifiers [-fpermissive]

您可能还想查看this related question

答案 3 :(得分:2)

operator=是一个const 可访问的成员函数,它返回一个可变的Margin对象。

因此,分配临时值是有效的,因为在EventManager.RegisterClassHandler(typeof(System.Windows.Controls.TextBox), System.Windows.Controls.TextBox.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(OnGotKeyboardFocus)); void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { var textBox = sender as System.Windows.Controls.TextBox; if (textBox != null && !textBox.IsReadOnly && e.KeyboardDevice.IsKeyDown(Key.Tab)) textBox.SelectAll(); } 上使用LostKeyboardFocus有效。在这种情况下,它没有副作用,基本上什么也没做。 C ++编译器的特定实现可能选择实现语义分析并警告您,但它完全超出了语言的范围。