见这个例子:
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==
方法?
答案 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-=
和类似的“扩充分配”。可能只有在允许非成员重载(禁止赋值和扩充赋值运算符)时才会出现逻辑问题。