std :: array <std :: vector>中的brace elision

Sva*_*zen 6 c++ list-initialization c++17

我正在编译使用g++C++ 17.我有以下内容:

std::array<std::vector<int>, 2> v = {{ {1,2}, {3,4} }};
Run Code Online (Sandbox Code Playgroud)

我不明白为什么如果我删除数组的双括号它不再工作.

std::array<std::vector<int>, 2> v = { {1,2}, {3,4} }; // Does not compile
Run Code Online (Sandbox Code Playgroud)

我理解一般是如何std::array工作和双括号的需要,但正如我正在编译C++ 17我期望支持elision发挥作用.

为什么括号不适用于此?

T.C*_*.C. 7

std::array<std::vector<int>, 2> 是有效的

struct array {
    std::vector<int> elems[2];
};
Run Code Online (Sandbox Code Playgroud)

elems是一个小分类就好了.问题在于,根据语言规则,如果初始化程序以a开头,{则始终假定您没有使用括号; 相反,{1, 2}被视为整个子聚集的初始化elems,试图初始化与第一个元素1,并用第二个元素2(这显然是无效的-你不能一个整数转换成vector-但不影响解释),并且{3, 4}是之后考虑了事物的初始化程序elems- 而且由于没有这样的事情,这是另一个错误.

使用不是braced-init-list的东西初始化第一个元素足以触发大括号省略:

std::array<std::vector<int>, 2> v = { std::vector<int>{1,2}, {3,4} }; 
Run Code Online (Sandbox Code Playgroud)

请注意,从规范的角度来看,库不保证std::array<T, N>从另一个以外的任何内容std::array<T, N>或"最多N个元素的类型可转换为T" 的列表进行初始化.这显然不包括braced-init-list,因为它们没有类型,实际上也不允许"双括号",因为这只是一个特殊情况,它有一个单独的元素是一个braced-init-list.

这是一个我们可能最好用代码指定它的区域.核心语言规则无法用语言轻松规范,实现细节也会漏掉 - 而且已经这样做了.

  • 形式上,它是未定义的行为:当用其他任何东西初始化`std :: array`时,标准定义没有行为.双括号不在"定义为工作"的情况下,因为它们实际上是一个初始化列表,包含没有类型的单个元素(内部braced-init-list).Brace elision一直回到C.`std :: array`与它无关.正式的UB肯定是一个缺陷; 问题是找到正确的词来定义行为,最好不要反复聚合初始化规则的几页. (2认同)

Sha*_*our 4

正如 TC 指出的,我最初的解释并不正确,允许省略大括号,请参阅[dcl.init.aggr]p15

可以在初始化列表中省略大括号,如下所示。如果初始化器列表以左大括号开头,则后续的以逗号分隔的初始化器子句列表将初始化子聚合的元素;初始化子句的数量多于元素的数量是错误的。但是,如果子聚合的初始值设定项列表不以左大括号开头,则仅从列表中获取足够的初始值设定项子句来初始化子聚合的元素;任何剩余的初始化子句都用于初始化当前子聚合是其元素的聚合的下一个元素。...

std::array根据array.overview

数组是一个聚合,可以使用最多 N 个元素进行列表初始化,这些元素的类型可转换为 T。

我们的情况并非如此。