为什么我可以使用操作符=而不是操作符=与c++ 11括号初始化器?

时间:2022-05-18 07:13:25

See this example:

看这个例子:

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
    {
    }
}

The line a={1,2} is fine. The braces are convert to a Foo to match the argument type of the implicit operator= method. It still works if operator= is user-defined.

行a={1,2}是可以的。括号被转换为Foo以匹配隐式运算符=方法的参数类型。如果操作符=是用户定义的,它仍然有效。

The line if (a=={1,2}}) errors as indicated.

如所示,如果(a={1,2})出错。

Why does the expression {1,2} not convert to a Foo to match the user-defined operator== method?

为什么表达式{1,2}不能转换为Foo以匹配用户定义的运算符==方法?

5 个解决方案

#1


41  

List-initialization cannot be used as an argument to an operator in the general case. Per Paragraph 8.5.4/1 of the C++11 Standard:

在一般情况下,初始化不能用作操作符的参数。根据c++ 11标准第8.5.4/1段:

[...] List-initialization can be used

[…可以使用列表初始化

— as the initializer in a variable definition (8.5)

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

— as the initializer in a new expression (5.3.4)

-作为新表达式中的初始值设定项(5.3.4)

— in a return statement (6.6.3)

-在报税表(6.6.3)

— as a for-range-initializer (6.5)

-作为测距初始化器(6.5)

as a function argument (5.2.2)

-作为函数参数(5.2.2)

— as a subscript (5.2.1)

-作为下标(5.2.1)

— as an argument to a constructor invocation (8.5, 5.2.3)

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

— as an initializer for a non-static data member (9.2)

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

— in a mem-initializer (12.6.2)

-在内存初始化器中(12.6.2)

on the right-hand side of an assignment (5.17)

-在作业的右边(5.17)

The last item explains why list-initialization is allowed on the right side of operator =, even though it is not allowed in general for an arbitrary operator.

最后一项解释了为什么在操作符=的右侧允许进行列表初始化,尽管对于任意操作符来说通常不允许这样做。

Because of the fifth item above, however, it can be used as an argument to a regular function call, this way:

但是,由于上面的第五项,它可以作为常规函数调用的参数,如下所示:

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

#2


7  

It's just simply not supported.

它只是不受支持。

Initializer lists are explicitly defined to be valid in initializations ([C++11: 8.5.4]), and assignments:

初始化列表在初始化([c++ 11: 8.5.4])中被显式地定义为有效,并且赋值:

[C++11: 5.17/9]: A braced-init-list may appear on the right-hand side of

[C+ 11: 5.17/9]:括号内的列表可能出现在右边

  • an assignment to a scalar, in which case the initializer list shall have at most a single element. The meaning of x={v}, where T is the scalar type of the expression x, is that of x=T(v) except that no narrowing conversion (8.5.4) is allowed. The meaning of x={} is x=T().
  • 对标量的赋值,在这种情况下,初始化器列表最多应该只有一个元素。x={v}的含义,其中T是表达式x的标量类型,是x=T(v)的含义,但不允许进行窄化转换(8.5.4)。x={}的含义是x=T()。
  • an assignment defined by a user-defined assignment operator, in which case the initializer list is passed as the argument to the operator function.
  • 由用户定义的赋值操作符定义的赋值,在这种情况下,初始化器列表作为参数传递给操作符函数。

There is no standard wording to allow other, arbitrary cases.

没有标准的措辞允许其他任意的情况发生。

If it were allowed, in this example, the type of {1,2} would be fairly ambiguous. It would be a complicated language feature to implement.

如果允许,在本例中,{1,2}的类型将相当模糊。这将是一个复杂的语言特性。

#3


4  

An explicit cast is required.

需要显式强制转换。

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

#4


0  

When you are using the expression containing the user defined type a and == operator Overloaded operator function gets called which as per definition you have given requires an argument of a reference of an object of class Foo

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

so your expression should be like a==b

所以表达式应该是a= b

where b is an object of class Foo

b是Foo类的对象

Here with this expression you will be able to compare data members of b and a and hence know if they are equal or not

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

#5


0  

No real reason.

没有真正的原因。

C++ is the result of a committee effort so sometimes strange but deliberate decisions may slip through because of complex political/sociological dynamics.

c++是委员会努力的结果,这种努力有时很奇怪,但由于复杂的政治/社会动态,经过深思熟虑的决定可能会悄悄通过。

C++ syntax is hard. Very hard. Almost unbelievably hard. There are rules even go like "if you can parse this arbitrarily long sequence of tokens as both this or that, then it's this".

c++语法是很难的。很努力。几乎都是令人难以置信的困难。甚至有一些规则是这样的:“如果你能把这个任意长的令牌序列解析成这个或那个,那么它就是这个”。

It took many years for compilers even to simply agree on what is C++ and what is not.

编译器甚至花了许多年才简单地确定什么是c++,什么不是。

In this case my wild guess is that they didn't like the idea that cases that looked very similar:

在这个案例中,我疯狂的猜测是他们不喜欢类似的案例:

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

would be handled differently so there is a special provision for assignment to allow the syntax.

会有不同的处理,所以有一个特殊的分配条款允许语法。

From a technical point of view I don't see what are the problems of allowing it for other operators too, and on the other hand if there are problems (e.g. for overloading, template instantiation etc.) I don't see how assignment can hope to escape them.

从技术的角度来看,我不知道允许其他操作符使用它有什么问题,另一方面,如果存在问题(例如重载、模板实例化等),我也不知道赋值如何能够避免它们。

EDIT

g++ allows using not only strict operator= but also operator+=, operator-= and similar "augmented assignment". May be the logical problems happens only if you allow non-member overloads (that are forbidden for assignment and augmented assignment operators).

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

#1


41  

List-initialization cannot be used as an argument to an operator in the general case. Per Paragraph 8.5.4/1 of the C++11 Standard:

在一般情况下,初始化不能用作操作符的参数。根据c++ 11标准第8.5.4/1段:

[...] List-initialization can be used

[…可以使用列表初始化

— as the initializer in a variable definition (8.5)

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

— as the initializer in a new expression (5.3.4)

-作为新表达式中的初始值设定项(5.3.4)

— in a return statement (6.6.3)

-在报税表(6.6.3)

— as a for-range-initializer (6.5)

-作为测距初始化器(6.5)

as a function argument (5.2.2)

-作为函数参数(5.2.2)

— as a subscript (5.2.1)

-作为下标(5.2.1)

— as an argument to a constructor invocation (8.5, 5.2.3)

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

— as an initializer for a non-static data member (9.2)

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

— in a mem-initializer (12.6.2)

-在内存初始化器中(12.6.2)

on the right-hand side of an assignment (5.17)

-在作业的右边(5.17)

The last item explains why list-initialization is allowed on the right side of operator =, even though it is not allowed in general for an arbitrary operator.

最后一项解释了为什么在操作符=的右侧允许进行列表初始化,尽管对于任意操作符来说通常不允许这样做。

Because of the fifth item above, however, it can be used as an argument to a regular function call, this way:

但是,由于上面的第五项,它可以作为常规函数调用的参数,如下所示:

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

#2


7  

It's just simply not supported.

它只是不受支持。

Initializer lists are explicitly defined to be valid in initializations ([C++11: 8.5.4]), and assignments:

初始化列表在初始化([c++ 11: 8.5.4])中被显式地定义为有效,并且赋值:

[C++11: 5.17/9]: A braced-init-list may appear on the right-hand side of

[C+ 11: 5.17/9]:括号内的列表可能出现在右边

  • an assignment to a scalar, in which case the initializer list shall have at most a single element. The meaning of x={v}, where T is the scalar type of the expression x, is that of x=T(v) except that no narrowing conversion (8.5.4) is allowed. The meaning of x={} is x=T().
  • 对标量的赋值,在这种情况下,初始化器列表最多应该只有一个元素。x={v}的含义,其中T是表达式x的标量类型,是x=T(v)的含义,但不允许进行窄化转换(8.5.4)。x={}的含义是x=T()。
  • an assignment defined by a user-defined assignment operator, in which case the initializer list is passed as the argument to the operator function.
  • 由用户定义的赋值操作符定义的赋值,在这种情况下,初始化器列表作为参数传递给操作符函数。

There is no standard wording to allow other, arbitrary cases.

没有标准的措辞允许其他任意的情况发生。

If it were allowed, in this example, the type of {1,2} would be fairly ambiguous. It would be a complicated language feature to implement.

如果允许,在本例中,{1,2}的类型将相当模糊。这将是一个复杂的语言特性。

#3


4  

An explicit cast is required.

需要显式强制转换。

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

#4


0  

When you are using the expression containing the user defined type a and == operator Overloaded operator function gets called which as per definition you have given requires an argument of a reference of an object of class Foo

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

so your expression should be like a==b

所以表达式应该是a= b

where b is an object of class Foo

b是Foo类的对象

Here with this expression you will be able to compare data members of b and a and hence know if they are equal or not

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

#5


0  

No real reason.

没有真正的原因。

C++ is the result of a committee effort so sometimes strange but deliberate decisions may slip through because of complex political/sociological dynamics.

c++是委员会努力的结果,这种努力有时很奇怪,但由于复杂的政治/社会动态,经过深思熟虑的决定可能会悄悄通过。

C++ syntax is hard. Very hard. Almost unbelievably hard. There are rules even go like "if you can parse this arbitrarily long sequence of tokens as both this or that, then it's this".

c++语法是很难的。很努力。几乎都是令人难以置信的困难。甚至有一些规则是这样的:“如果你能把这个任意长的令牌序列解析成这个或那个,那么它就是这个”。

It took many years for compilers even to simply agree on what is C++ and what is not.

编译器甚至花了许多年才简单地确定什么是c++,什么不是。

In this case my wild guess is that they didn't like the idea that cases that looked very similar:

在这个案例中,我疯狂的猜测是他们不喜欢类似的案例:

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

would be handled differently so there is a special provision for assignment to allow the syntax.

会有不同的处理,所以有一个特殊的分配条款允许语法。

From a technical point of view I don't see what are the problems of allowing it for other operators too, and on the other hand if there are problems (e.g. for overloading, template instantiation etc.) I don't see how assignment can hope to escape them.

从技术的角度来看,我不知道允许其他操作符使用它有什么问题,另一方面,如果存在问题(例如重载、模板实例化等),我也不知道赋值如何能够避免它们。

EDIT

g++ allows using not only strict operator= but also operator+=, operator-= and similar "augmented assignment". May be the logical problems happens only if you allow non-member overloads (that are forbidden for assignment and augmented assignment operators).

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