统一初始化是一个重要且有用的C ++ 11功能。但是,您无法在以下任何地方使用{}
:
std::vector<int> a(10, 0); // 10 elements of value zero
std::vector<int> b({10, 0}); // 2 elements of value 10 and 0 respectively
std::vector<int> c{10, 0}; // 2 elements of value 10 and 0 respectively
std::vector<int> d = {10, 0}; // 2 elements of value 10 and 0 respectively
auto e(0); // deduced type is int
auto f = 0; // deduced type is int
auto g{0}; // deduced type is std::initializer_list<int>
auto h = {0}; // deduced type is std::initializer_list<int>
注意到例如聚合初始化 std::arrays
需要使用{{}}
,在我看来,选择哪个矢量构造函数的整个问题可以通过要求{{}}
来避免调用构造函数取std::initializer_list
:
std::vector<int> i{10, 0}; // 10 elements of value zero
std::vector<int> j{{10, 0}}; // 2 elements of value 10 and 0 respectively
std::vector<int> k = {10, 0}; // 2 elements of value 10 and 0 respectively
auto l{0}; // deduced type is int
auto m{{0}}; // deduced type is std::initializer_list<int>
auto n = {0}; // deduced type is std::initializer_list<int>
我确定已经讨论过了,所以对此有什么理由?标准提案的引用/链接最好作为答案。
更新。 - N2532中有一点说明:
(3)可能令人讨厌的歧义情况仅发生在短初始化列表[...]
上(5)语言规则为什么要强制程序员想要简洁 和歧义控制(完全有理由)写更多 请那些喜欢(出于完美的理由)更多的程序员 明确 - 可以吗?
[...]
假设程序员期望调用f(X)。怎么可能f(Y) “劫持”一个电话?
(4)假设X没有初始化列表构造函数,但Y没有。在 在这种情况下,初始化列表构造函数的优先级是有利的 劫机者(记得我们以某种方式假设程序员 期望f(X)被称为)。这类似于有人期待的 f(y)使用用户定义的转换来调用f(X)并且有人来 以及完全匹配的f(Y)。 我认为这是公平的 期望使用{...}的人会记住这种可能性 初始化列表构造函数。 [强调我的]
我猜关键在于可以是,这意味着您不必使用统一初始化。正确使用{}
很难:
您不仅要检查要调用的构造函数,还要检查任何构造函数,这些构造函数可能会获得(并且可能会)胜过它的initializer_list
; < / p>
如果您使用{}
编写代码,并且将来会添加一个std::initializer_list
构造函数,您的代码可能会破坏,并且默默地。
即使你有一个带有构造函数A
和A(int, bool)
的类A(std::initializer_list<double>)
,后者也将被选为前者A a{0, false};
(IMO很疯狂),所以我发现它真的很难在具有或可能的(具有所需的水晶球超级大国)initializer_list
构造函数的类上使用统一初始化。
你的代码可以默默地破解我的事实。
答案 0 :(得分:11)
这是Stroustrup在这个问题上所说的话:
统一和普遍并不仅仅是第四种选择。它被设计为 初始化语法,并且遗憾的是[不]可用于所有遗留代码,尤其是
vector
。如果我今天设计vector
,你就不得不说vector<int> {Count{9}};
这样的事情来计算。
回答问题“是问题向量还是{} -init语法?”
这是矢量设计:如果我今天设计
vector
,你就不得不说vector<int> {Count{9}};
之类的东西来计算。更普遍的问题是,同一类型的几个语义上不同的参数最终会导致混淆,特别是如果它们可以出现。例如:
vector<int> v(7,2); // 7 (a count) element with the value 2
答案 1 :(得分:4)
(这不是一个真正的答案,只是讨论我在这个问题上的想法。)
我认为我希望编译器在出现歧义的情况下发出警告,建议开发人员使用({ })
(如果他们确实需要initializer_list)或( )
如果他们不这样做。如果MostVexingParse存在风险,请发出额外警告! - 或许建议(( ))
来避免这种情况?
(以下&#39;故事&#39;可能不是基于如何开发该功能的正确历史年表,但它是我如何理解编译器中的当前规则。)
一开始我们有构造函数:
type t (...);
然后我们想到允许{
提供一个文字集合以供构造函数(以及其他地方)使用。
type t ( {...} );
...以及构造函数中的新initializer_list
类型以匹配此内容。
然后,我们被允许用( )
替换{ }
,以避免最令人烦恼的解析:
type t { ... };
type t { {...} };
到目前为止,这么好。纯语言的扩展。
最后,有争议的&#39;另外,当编译器看到{ ... }
(作为构造函数)时,它将首先尝试将其重写为({ ... })
(如果存在则调用initializer_list),然后再回到( ... )
。如果两种选择都被认为同样好,我认为我更喜欢如果两种选择都可能会出现警告或错误。