我不明白为什么初始化器列表不能用于运营商的RHS。考虑一下:
class foo { };
struct bar
{
template<typename... T>
bar(T const&...) { }
};
foo& operator<<(foo& f, bar const&) { return f; }
int main()
{
foo baz;
baz << {1, -2, "foo", 4, 5};
return 0;
}最新的Clang (也是gcc)抱怨道:
clang.cc:14:9: error: initializer list cannot be used on the right hand side of operator '<<'
baz << {1, -2, "foo", 4, 5};
^ ~~~~~~~~~~~~~~~~~~~~
^ ~~~~~~~~~~~~~~~为什么C++标准会禁止这样做呢?或者换句话说,为什么这会失败,而不是
baz << bar{1, -2, "foo", 4, 5};发布于 2012-07-12 14:10:06
实际上,C++11的最终版本不支持在二元运算符的右侧(或左侧)使用初始化器列表。
首先,初始化器列表不是本标准§5中定义的表达式。函数的参数以及二元运算符的参数通常必须是表达式,§5中定义的表达式的语法不包括花括号初始化列表的语法(即纯初始化列表;请注意,typename后跟大括号初始化列表,例如bar {2,5,"hello",7}是一个表达式)。
为了能够方便地使用纯初始化器列表,本标准定义了各种例外,总结如下(非规范)注释:
§8.5.4/1 ...注意:可以使用列表初始化
-作为变量定义中的初始化器(8.5)
-作为新表达式中的初始化器(5.3.4)
-在返回语句中(6.6.3)
-作为函数参数(5.2.2)
-作为下标(5.2.1)
-作为构造函数调用的参数(8.5,5.2.3)
-作为非静态数据成员的初始值设定项(9.2)
-在内存初始化器中(12.6.2)
-在作业的右侧(5.17)
..。
上面的第四项明确地允许纯初始化器列表作为函数参数(这就是operator<<(baz, {1, -2, "foo", 4, 5});工作的原因),第五项允许在下标表达式中使用它(即作为operator[]的参数,例如mymap[{2,5,"hello"}]是合法的),最后一项允许它们位于赋值的右侧(但不是一般的二元运算符)。
对于像+,*或<<这样的二元运算符,没有这样的例外,因此你不能在它们的两侧放置一个纯初始化器列表(即前面没有类型名的列表)。
至于这个的原因,Stroustrup和Dos Reis在2007年发表的一篇draft/discussion paper N2215提供了许多关于各种上下文中初始化器列表的问题的见解。具体来说,有一节是关于二元运算符的(6.2节):
考虑初始化器列表的更一般用法。例如:
V= v+{3,4};v= {6,7}+v;
当我们将运算符视为函数的语法糖时,我们自然会认为上面的操作等同于
V= operator+(v,{3,4});v= operator+({6,7},v);
因此,将初始化器列表的使用扩展到表达式是很自然的。在很多情况下,初始化器列表和运算符的组合是一种“自然”的符号。
然而,编写一个允许任意使用初始化器列表的LR(1)语法并不是一件容易的事情。块也以{开头,因此允许初始化器列表作为表达式的第一个(最左边)实体将导致语法混乱。
在下标和语法的类似孤立部分中,允许初始化器列表作为二元运算符的右操作数是微不足道的。真正的问题是在不允许;{1,2}+b;的情况下允许;a={1,2}+b;作为赋值语句。我们怀疑,允许初始化器列表作为右手参数,但也不允许sic作为大多数操作符的左手参数,这太杂乱无章了,...
换句话说,在右边的上没有启用初始化器列表,因为在左边的上没有启用它们,在左边也没有启用它们,因为这会给解析器带来太大的挑战。
我想知道这个问题是否可以通过为初始化器列表语法选择一个不同的符号而不是花括号来简化。
https://stackoverflow.com/questions/11420448
复制相似问题