为什么我可以使用operator =但不使用operator == C ++ 11 brace-initializers?

时间:2013-04-23 12:17:48

标签: c++ c++11

见这个例子:

struct Foo
{
    int a;
    int b;

    bool operator == (const Foo & x)
    {
        return a == x.a && b == x.b;
    }
};

int main ()
{
    Foo a;

    a = {1, 2};

    if (a == {1, 2}) // error: expected primary-expression before ‘{’ token
    {
    }
}

a={1,2}行很好。大括号将转换为Foo以匹配隐式operator=方法的参数类型。如果operator=是用户定义的,它仍然有效。

指示的行if (a=={1,2}})错误。

为什么表达式{1,2}未转换为Foo以匹配用户定义的operator==方法?

5 个答案:

答案 0 :(得分:41)

在一般情况下中,列表初始化不能用作运算符的参数。根据C ++ 11标准的第8.5.4 / 1段:

  

[...]可以使用列表初始化

     

- 作为变量定义中的初始化器(8.5)

     

- 作为新表达式(5.3.4)中的初始化器

     

- 在一份退货声明(6.6.3)

中      

- 作为for-range-initializer(6.5)

     

- 作为函数参数(5.2.2)

     

- 作为下标(5.2.1)

     

- 作为构造函数调用的参数(8.5,5.2.3)

     

- 作为非静态数据成员的初始化程序(9.2)

     

- 在mem-initializer(12.6.2)

中      

- 作业右侧的 (5.17)

最后一项解释了为什么在operator =的右侧允许列表初始化,即使一般情况下不允许任意操作符。

由于上面的第五项,它可以用作常规函数调用的参数,这样:

if (a.operator == ({1, 2}))

答案 1 :(得分:7)

它只是不受支持。

初始化程序列表在初始化[C++11: 8.5.4])和分配中明确定义为有效:

  

[C++11: 5.17/9]: braced-init-list 可能会出现在

的右侧      
      
  • 对标量的赋值,在这种情况下,初始化列表最多只能包含一个元素。 x={v}的含义T是表达式x的标量类型,是x=T(v)的含义,但不允许缩小转换(8.5.4)。 x={}的含义为x=T()
  •   
  • 由用户定义的赋值运算符定义的赋值,在这种情况下,初始化列表作为参数传递给运算符函数。
  •   

没有标准的措辞允许其他任意案件。

如果允许,在此示例中,{1,2}的类型将是相当模糊的。实施这将是一个复杂的语言功能。

答案 2 :(得分:4)

需要显式演员。

if (a == (Foo){1, 2})
{
}

答案 3 :(得分:0)

当您使用包含用户定义类型a和==运算符的表达式时 调用重载的操作符函数,根据您的定义,您需要一个Foo类对象引用的参数

所以你的表达式应该像== b

其中b是Foo类的对象

使用此表达式,您将能够比较b和a的数据成员,从而知道它们是否相等

答案 4 :(得分:0)

没有真正的理由。

C ++是委员会努力的结果,所以有时候很奇怪,但由于复杂的政治/社会动态,故意的决定可能会漏掉。

C ++语法很难。很难。几乎令人难以置信的艰难。有些规则甚至可以说“如果你可以将这个任意长的令牌序列解析为这个或那个,那就是这个”。

编译器花了很多年才简单地同意什么是C ++,什么不是。

在这种情况下,我的猜测是他们不喜欢看起来非常相似的案例:

MyClass x = {...};
MyClass y; y = {...};

将以不同的方式处理,因此有一个特殊的赋值用于允许语法。

从技术角度来看,我没有看到将其允许用于其他运营商的问题,另一方面,如果存在问题(例如,用于重载,模板实例化等),我看不到任务如何能够逃脱它们。

修改

g ++不仅允许使用严格的operator=,还允许使用operator+=operator-=和类似的“扩充分配”。可能只有在允许非成员重载(禁止赋值和扩充赋值运算符)时才会出现逻辑问题。