在C++14标准中,std::array
的初始化可以使用单括号(参见http://en.cppreference.com/w/cpp/container/array):
然而,这对于std::pair
的std::array
不起作用。
为什么这些工作:
std::pair<int, int> p { 1, 2 };
std::array<int, 3> a {1, 2, 3};
但这并不起作用:
std::array<std::pair<int, int>, 3> b {{1, 11}, {2, 22}, {3, 33}};
当这个又能用的时候?
std::array<std::pair<int, int>, 3> b {{{1, 11}, {2, 22}, {3, 33}}};
此外,为了完成,一个好的旧数组的初始化确实可以使用单大括号
std::pair<int, int> c[3] {{1, 11}, {2, 22}, {3, 33}};
5条答案
按热度按时间pdsfdshx1#
这看起来是一个解析上的歧义,有点类似于著名的most vexing parse。我怀疑现在的情况是:
如果你写
编译器有两种解释语法的方法:
1.执行全括号初始化(这意味着最外面的大括号引用
std::array
的聚合初始化,而第一个最里面的大括号初始化std::array
的内部成员表示,这是一个真实的的C数组)。这将无法编译,因为1
随后无法初始化std::pair<int, int>
(所有大括号都用完了)。clang将给予一个编译器错误,准确地指出:还请注意,如果没有要初始化的内部成员聚合,即
会像聚合初始化一样编译得很好。
1.(你的意思是这样的。)你执行了一个大括号省略的初始化,最里面的大括号因此是用于单个对的聚合初始化,而内部数组表示的大括号被省略了。请注意,即使没有这种二义性,正如在rustyx's answer中正确指出的那样,括号省略的规则也不适用,因为
std::pair
不是聚合类型,所以程序仍然是病态的。编译器将首选选项1。通过提供额外的大括号,可以执行全大括号初始化并消除任何语法歧义。
f0brbegy2#
C++14大括号省略规则仅适用于子聚合初始化。
例如这样的工作:
在这里,集合的集合可以被列表初始化,而不需要额外的括号。
但是
std::pair
不是一个聚合(它有构造函数),因此该规则不适用。这意味着如果没有大括号省略规则,
std::array
本身就是一个内部有数组的聚合,需要一组额外的大括号才能 * 列表初始化 *。请记住,类模板array
是这样实现的:要在不使用大括号省略规则的情况下 list-initialize 它,您需要一组额外的大括号来访问
elems
成员。zzoitvuj3#
如果没有双大括号,该语句就是二义性的。请考虑以下代码:
如果第一个定义中没有双括号,编译器将把
{ {1,2} }
视为array<int, 2>
的 * 标量初始化列表 *。你需要声明一个显式的 * 嵌套的花括号初始化列表 *,以便编译器识别内部列表也是 * 聚合初始化的 *(与标量初始化),使得它可以构造std::pair
的数组。uqcuzwp84#
理论上
std::array
应该用聚合初始化来初始化。实际上是这样的:是这个的语法糖:
正如你所看到的,在第一个中,我似乎用值初始化数组,但它实际上是用花括号初始化列表的聚合初始化。在第二种情况下,这是显而易见的。所以这只是开始。
好吧,那么为什么这不起作用呢?
简单地说,编译器无法区分你用什么类型的语法来初始化数组。
{1, 11}
可以被解释为初始化列表并使用第一个版本,也可以被解释为一对并使用第二个版本。此代码:
消除歧义。
来源:http://en.cppreference.com/w/cpp/language/aggregate_initialization
gwo2fgha5#
我来猜猜。
std::array<T,n>
的初始化器列表应该是T
的列表(或者可以简单地构造为T
)。所以你可以但那太冗长了为了得到您想要的到
std::pair<int,int>
的转换,您需要提供一个初始化器列表,所以我不能进一步为这一点辩护,但请注意,
std::vector<T, Allocator>::vector( std::initializer_list<T>, const Allocator& alloc=Allocator())
是定义的,但std::array<T,n>::array( std::initializer_list<T> )
不是。也没有定义std::pair<U,T>::pair( std::initializer_list<??> )
。