我想知道,为什么在以下代码中声明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
都是聚合。来自aggregate initialization on cppreference.com:
如果initializer子句是嵌套的braced-init-list(不是表达式且没有类型),则相应的类成员是 本身是一个聚合:聚合初始化是递归的。
为什么std::array
的初始化不能编译?
答案 0 :(得分:8)
聚合初始化中的大括号在很大程度上是可选的,因此您可以写:
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}
是S[2]
std_arr
成员的有效初始化资源。 {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上涵盖,目前尚未得到保证。
答案 1 :(得分:3)
由于问题标记为C ++ 14,我将引用N4140。在[array]中,它表示std::array
是一个聚合:
2
array
是一个可以使用。初始化的聚合(8.5.1) 语法array a = { initializer-list };其中 initializer-list 是逗号分隔的列表,最多包含
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}};
没有形成错误。