std::array 的嵌套聚合初始化
Nested aggregate initialization of std::array
我想知道,为什么在以下代码中声明std_arr
会产生错误,而c_arr
编译良好:
struct S { int a, b; };
S c_arr[] = {{1, 2}, {3, 4}}; // OK
std::array<S, 2> std_arr = {{1, 2}, {3, 4}}; // Error: too many initializers
std::array
和S
都是聚合。从聚合初始化到 cppreference.com:
如果初始值设定项子句是嵌套的大括号初始化列表(它不是表达式,也没有类型(,则相应的类成员为 本身是一个聚合:聚合初始化是递归的。
为什么std::array
的初始化不编译?
聚合初始化中的大括号在很大程度上是可选的,因此您可以编写:
S c_arr[] = {1, 2, 3, 4}; // OK
std::array<S, 2> std_arr = {1, 2, 3, 4}; // OK
但是,如果您确实添加了大括号,则会将大括号应用于下一个子对象。不幸的是,当你开始嵌套时,这会导致愚蠢的代码有效,而像你这样的合理代码无效。
std::array<S, 2> std_arr = {{1, 2, 3, 4}}; // OK
std::array<S, 2> std_arr = {1, 2, {3, 4}}; // OK
std::array<S, 2> std_arr = {1, {2}, {3, 4}}; // OK
这些都没关系。 {1, 2, 3, 4}
是 std_arr
的 S[2]
成员的有效初始化器。 {2}
是可以的,因为它是初始化int
的尝试,而{2}
是有效的初始化器。 {3, 4}
被视为 S
的初始化器,它对此也是有效的。
std::array<S, 2> std_arr = {{1, 2}, {3, 4}}; // error
这是不行的,因为{1, 2}
被视为S[2]
成员的有效初始化器。其余 int
个子对象初始化为零。
然后您有 {3, 4}
,但没有更多的成员要初始化。
正如评论中指出的,
std::array<S, 2> std_arr = {{{1, 2}, {3, 4}}};
也有效。嵌套{{1, 2}, {3, 4}}
是S[2]
成员的初始化器。{1, 2}
是第一个S
元素的初始化器。{3, 4}
是第二个S
元素的初始化器。
我在这里假设std::array<S, 2>
包含一个类型 S[2]
的数组成员,它在当前的实现中确实如此,并且我相信它可能会得到保证,但它之前已经在 SO 上涵盖过,目前无法保证。
由于该问题被标记为 C++14,我将引用 N4140。在 [array] 中,它说std::array
是一个聚合:
2
array
是一个聚合 (8.5.1(,可以使用 语法数组 a = { 初始值设定项列表 };其中初始值设定项列表是最多包含
N
个元素的逗号分隔列表 其类型可转换为T
.
通常,人们同意您需要一对额外的外大括号来初始化底层聚合,这看起来像 T elems[N]
.在第 3 段中,它解释说这是出于说明目的,而不是界面的实际部分。然而,在实践中,libstdc++ 和 Clang 是这样实现的:
template<typename _Tp, std::size_t _Nm>
struct __array_traits
{
typedef _Tp _Type[_Nm];
static constexpr _Tp&
_S_ref(const _Type& __t, std::size_t __n) noexcept
{ return const_cast<_Tp&>(__t[__n]); }
};
template<typename _Tp, std::size_t _Nm>
struct array
{
/* Snip */
// Support for zero-sized arrays mandatory.
typedef _GLIBCXX_STD_C::__array_traits<_Tp, _Nm> _AT_Type;
typename _AT_Type::_Type _M_elems;
铛:
template <class _Tp, size_t _Size>
struct _LIBCPP_TYPE_VIS_ONLY array
{
/* Snip */
value_type __elems_[_Size > 0 ? _Size : 1];
在 C++11 和 C++14 之间有关于聚合初始化的更改,但是不会进行任何更改:
std::array<S, 2> std_arr = {{1, 2}, {3, 4}};
不是格式错误。
- 标准::unordered_map 中的 std::array 的值初始化
- 将初始化器列表/聚合初始化转发到 std::array 成员
- 为什么 char 可以在 std::array 中初始化为 nullptr,而不是单独初始化?
- 为什么不能用两层列表初始值设定项初始化 2D std::array?
- 如何在类的初始值设定项列表中初始化 std::array,而不对数组的大小进行硬编码
- std::array 大括号如何初始化?
- 我正在使用dev c ++,但收到错误(C++98'array'必须由构造函数初始化)
- 为什么我必须在初始化 std::array<SomeStruct, size> 时指定每个项目的类型C++
- 我可以在初始化之前使用 std::array 成员变量中的 data() 指针吗?发出警告
- 使用 constexpr 初始化 std.array 中的对象
- 使用 std::make_shared 初始化 std::shared_ptr 将 std::array 作为参数
- 初始化 std::initializer_list 通过 std:: 初始化 std::p air 在初始化 std::array 时不起作用?
- 当 T 不可默认构造时,构造函数初始值设定项列表中 std::array<T,N> 的初始化
- 在构造函数中初始化私有 std::array 成员
- 使用元编程递归初始化 std::array
- 使用常量值初始化 std::array
- 使用 constexpr 和 std::array 进行静态初始化来替换动态初始化的 std::vector 的闰年
- 是否可以以编程方式初始化 constexpr std::array 成员
- 使用声明中的元素类型隐式初始化 std::array
- 初始化 **Array 以及标题中实际需要的内容,以便它通过