为什么不能使用两层列表初始化程序来初始化2D std :: array?

时间:2018-09-08 02:49:17

标签: c++ stdarray list-initialization

有人可以帮助我理解为什么我的编译器不能/不可以推断出这一点吗? (使用g ++ 7.3)

不起作用:

#include <array>
std::array<std::array<double,2>,2> f() {
 return {{0,0},{0,0}};
}

工作正常:

#include <array>
std::array<std::array<double,2>,2> f() {
 return {std::array<double,2>{0,0},{0,0}};
}

同样奇怪的是,这也失败了:

#include <array>
std::array<std::array<double,2>,2> f() {
 return std::array<std::array<double,2>,2>{{0,0},{0,0}};
}

@ 1201ProgramAlarm指出,添加另一组花括号是可行的:

#include <array>
std::array<std::array<double,2>,2> f() {
 return {{{0,0},{0,0}}};
}

它正在使用聚合初始化,因为std::array没有brace-init-list的构造函数。很好,但是为什么/如何运作?

std::array<double,2> x{1,2};

为什么要处理这种情况但不能处理嵌套的情况?

1 个答案:

答案 0 :(得分:7)

容器std::array等效于一个包含C数组的结构(实现可能不会以这种方式实现std::array,但应保证语义相同),因此应对其进行初始化两层大括号,即

#include <array>
std::array<std::array<double,2>,2> f() {
   return {{{{0,0}},{{0,0}}}};
} 

当然,可以像我们通常对2D数组所做的那样,删除初始化列表中的括号:

int arr[2][2] = {0,1,2,3};

...但是,以省略号之前的省略括号开头的初始化列表不应该以省略之后的左括号开头。换句话说,如果初始化列表以左花括号开头,则编译器将不会考虑此初始化列表已消除最外面的花括号的可能性。

在初始化程序{{0,0},{0,0}}中,子初始化程序{0,0},{0,0}以左花括号开头,因此可用于初始化C数组本身。但是,列表中有两个子句,而只有一个C数组,则会发生错误。

在初始化程序{std::array<double,2>{0,0},{0,0}}中,子初始化程序std::array<double,2>{0,0},{0,0}并非以左花括号开头,因此可以用来初始化C数组的元素,这很好(递归地, {0,0}可以初始化std::array<double,2>,因为子初始化程序0,0并非以左括号开头。


一个建议:使用括号的规则,您可以删除所有内部括号,就像我们通常对2D数组所做的一样:

#include <array>
std::array<std::array<double,2>,2> f() {
   return {0,0,0,0};
}