Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 初始化列表中的隐式类型转换在一种情况下编译,但在另一种情况下不编译_C++_C++11 - Fatal编程技术网

C++ 初始化列表中的隐式类型转换在一种情况下编译,但在另一种情况下不编译

C++ 初始化列表中的隐式类型转换在一种情况下编译,但在另一种情况下不编译,c++,c++11,C++,C++11,我定义了以下类: class A { int a; public: A(int _a = 0) :a(_a){} A(initializer_list<int> il) :a(il.size()){} friend A operator+(const A& a1, const A& a2); }; A operator+(const A& a1, const A& a2){ return A(); } 可以编译,但是下

我定义了以下类:

class A {
    int a;
public:
    A(int _a = 0) :a(_a){}
    A(initializer_list<int> il) :a(il.size()){}
    friend A operator+(const A& a1, const A& a2);
};
A operator+(const A& a1, const A& a2){ return A(); }
可以编译,但是下面

A a;
a + {3, 4, 5};
无法编译。错误消息是“
error C2059:syntax error:'{'
”和“
error C2143:syntax error:missing';”在“{'
”之前

这两个客户端代码都尝试进行隐式类型转换,从初始化列表
{3,4,5}
类A
,但第一个成功,而第二个代码段失败。我不理解为什么

你能解释一下吗

我正在使用MS Visual Studio 2013更新4

[编辑] 以下是阅读评论和其他相关材料后的后续行动。我想我的问题现在可以归结为以下几点:
我知道在二进制表达式的RHS中不允许使用括号init list,在函数调用中也允许使用括号init list。问题是,我认为二进制表达式,比如说,
arg1+arg2
由编译器内部转换为函数调用
操作符+(arg1,arg2)
,尤其是当arg1是类类型时。因此,在这一点上,二进制表达式和函数调用之间没有区别。因此,我能找到的唯一解释是,在这种二进制表达式到函数调用的转换之前应用了一个阻止规则,该规则特别检查第二个参数是否为braC.init列表或不。如果是,转换为等效函数调用将被禁止,并产生错误。我怀疑这些猜想是否真实,如果是,它是特定于C++标准编写的吗?谢谢所有参与我的问题的人。< /P> < P>由CLAN生成的错误信息非常清楚:

错误:不能在运算符“+”的右侧使用初始值设定项列表。

查看C++11标准,我发现(8.5.4/1[dcl.init.list]):

注意:可以使用列表初始化

  • 作为变量定义中的初始值设定项(8.5)
  • 作为新表达式中的初始值设定项(5.3.4)
  • 在返回语句中(6.6.3)
  • 作为函数参数(5.2.2)
  • 作为下标(5.2.1)
  • 作为构造函数调用的参数(8.5、5.2.3)
  • 作为非静态数据成员的初始值设定项(9.2)
  • 在mem初始值设定项中(12.6.2)
  • 在作业的右侧(5.17)

因此,我猜括号内的init list只能在上面列出的情况下使用。
operator+(a,{1,2,3})
因情况4而起作用。
a={1,2,3}
因最后一种情况而起作用。但是没有提及
a+{1,2,3}
.So no.

我试图查看标准,找出它不允许编写
表达式+带括号的init list
的原因,我找到的第一条是示例中的注释

§5.1.2(4)

大括号的init列表不是表达式

并且它不满足主表达式的要求。但它可以用于后缀表达式:

++
这样的二进制运算符期望表达式位于左侧和右侧,因此
表达式+带括号的init list
不适合c++语法

但是大括号的init列表可以出现在赋值的右侧,因为它需要一个初始值设定项子句:

assignment-expression:
    logical-or-expression assignment-operator initializer-clause
initializer-clause:
    assignment-expression
    braced-init-list
因此,您可以使用运算符+=:

A operator+=(A& a1, const A& a2){ return A(); }
int main() {
    A a;
    a + A{3, 4, 5};
    a += {3, 4, 5};
}

这让我想起了运算符的答案:{3,4,5}不是类类型。因此没有隐式转换。语法上,
{3,4,5}
是一个大括号的初始化列表。大括号的初始化列表不是一个表达式;语法只允许它出现在有限的地方,它不能出现在整数文本可能出现的任何地方。特别是,它可以作为函数调用的参数,并显式允许出现在赋值运算符的右侧(5.18/9)这里有一个很好的答案:但是为什么我们不能将
a+{1,2,3}
解释为
operator+(a,{1,2,3})
并应用案例4?这个转换(从
arg1+arg2
operator+(arg1,arg2)
)是一个普通的重载运算符定义的概念。@ USE280121,我不是编译器编写者。所以我不能给你一个确切的答案。C++解析是复杂的。只需解释<代码> A+{ 1, 2, 3 } /COD> > <代码>运算符+(A,{ 1, 2, 3 })。对于C++普通用户来说,这听起来是合理的,但对于编写引擎程序的人来说,这并不是很简单。
assignment-expression:
    logical-or-expression assignment-operator initializer-clause
initializer-clause:
    assignment-expression
    braced-init-list
A operator+=(A& a1, const A& a2){ return A(); }
int main() {
    A a;
    a + A{3, 4, 5};
    a += {3, 4, 5};
}