C++ 初始值设定项列表和运算符的RHS

C++ 初始值设定项列表和运算符的RHS,c++,c++11,operators,initializer-list,C++,C++11,Operators,Initializer List,我不明白为什么不能在操作员的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, "

我不明白为什么不能在操作员的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;
}
class foo{};
结构条
{
模板
bar(T常数&…){}
};

foo&operator实际上,C++11的最终版本不允许在二进制运算符的右侧(或左侧)使用初始值设定项列表

首先,初始值设定项列表不是本标准§5中定义的表达式。函数的参数以及二进制运算符的参数通常必须是表达式,§5中定义的表达式语法不包括大括号初始值列表的语法(即纯初始值设定项列表;请注意,类型名后跟大括号初始值列表,例如
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)的初始值设定项
-在mem初始值设定项(12.6.2)
-在作业的右侧(5.17)
[……]


上面的第四项明确允许纯初始值设定项列表作为函数参数(这就是为什么
operator实际上,C++11的最终版本不允许在二进制运算符的右侧(或左侧)使用初始值设定项列表

首先,初始值设定项列表不是本标准§5中定义的表达式。函数的参数以及二进制运算符的参数通常必须是表达式,§5中定义的表达式语法不包括大括号初始值列表的语法(即纯初始值设定项列表;请注意,类型名后跟大括号初始值列表,例如
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)的初始值设定项
-在mem初始值设定项(12.6.2)
-在作业的右侧(5.17)
[……]



上面的第四项明确允许纯初始值设定项列表作为函数参数(这就是为什么
operator因为您没有重载
operator,所以希望这相当于
baz如果这是您想要的行为,也许您应该尝试为
bar
提供一个非显式构造函数,该构造函数采用单个
初始值设定项列表
。这无法工作,因为
初始值设定项列表
正好具有ne模板参数,而不是具有多个参数类型的可变构造函数。有趣的是:
operator因为你没有重载
operator,所以我希望这相当于
baz如果这是你想要的行为,也许你应该试着给
bar
一个非显式构造函数,它只包含一个参数
initializer\u list
。这不起作用,因为
initializer\u list
只有一个模板参数,而变量构造函数有多个参数类型。有趣的是:
运算符不同的符号可能会使更多的事情成为可能,但是
{}
是从C89继承的数组初始值设定项和POD结构初始值设定项的自然扩展。感谢这个解释-我搜索了十进制运算符
true?{1,2,3}:{4,5,6}
-这不仅仅是二进制运算符的问题…@PiotrNycz这可能不是解析问题,而是类型推断问题。三元运算符的两个备选方案都需要在一个通用类型上达成一致,并且还必须确定结果值类别。大括号模糊了程序的含义。最好是在
?:
中显式,并将类型名称放在
{
之前,这不会牺牲任何表达能力。@jogojapan你认为这种理由——禁止RHS,因为我们不能两者兼得——是合理的吗?这不是一种“善的完美”吗毕竟,它是一个强大的功能,仍然只对RHS有用。例如,对于OP示例RHS来说,交换参数就足够了!jogojapan是的,我不认为RHS只是一个“混球”-这里更需要演绎。我已经开始讨论,希望重新审视严苛的规则,一个不同的符号可能会使更多的事情成为可能,但是
{}
是从C89继承的数组初始值设定项和POD结构初始值设定项的自然扩展。感谢这个解释-我搜索了十进制运算符
true?{1,2,3}:{4,5,6}
-这不仅仅是二进制运算符的问题…@PiotrNycz这可能不是解析问题,而是类型推断问题。三元运算符的两个备选方案都需要在一个通用类型上达成一致,并且还必须确定结果值类别。大括号模糊了程序的含义。最好是在
?:
中显式,并将类型名放在
{
之前,这不会牺牲任何表达能力。@jogojapan您认为这是禁止RHS b的理由吗
clang.cc:14:9: error: initializer list cannot be used on the right hand side of operator '<<'
    baz << {1, -2, "foo", 4, 5};
    ^  ~~~~~~~~~~~~~~~~~~~~

    ^  ~~~~~~~~~~~~~~~
baz << bar{1, -2, "foo", 4, 5};
v = v+{3,4};
v = {6,7}+v;
v = operator+(v,{3,4});
v = operator+({6,7},v);