C++11:如何正确初始化std::array?

92
如果我按照以下方式初始化std::array,编译器会警告我缺少大括号
std::array<int, 4> a = {1, 2, 3, 4};

这个修复了问题:

std::array<int, 4> a = {{1, 2, 3, 4}};

这是警告信息:

missing braces around initializer for 'std::array<int, 4u>::value_type [4] {aka int [4]}' [-Wmissing-braces]

这只是我的gcc版本中的一个错误吗,还是故意的?如果是故意的,为什么?


3
std::array 是一个聚合体。但我认为将来可能会让它能够使用单个集合。 - chris
1
@chris 你具体是什么意思? - Byzantian
5
你知道如何通过struct S {int i; int j;};S s = {5, 6};进行初始化吗?这就是聚合初始化。std::array 包含一个内建数组,可以通过初始化列表进行初始化,也就是内部集合所做的事情。外部集合用于聚合初始化。 - chris
@chris 所以在我的情况下,“{1, 2, 3, 4}”只是一个std::initializer_list对象,它本身必须放置在实际的初始化大括号中? - Byzantian
可能是When can outer braces be omitted in an initializer list?的重复问题。 - underscore_d
显示剩余3条评论
5个回答

63
这是std::array的基本实现:
template<typename T, std::size_t N>
struct array {
    T __array_impl[N];
};

它是一个聚合结构,其唯一的数据成员是传统数组,因此内部的 {} 用于初始化内部数组。

在某些情况下,聚合初始化允许使用花括号省略(但通常不建议这样做),因此在这种情况下只能使用一个花括号。在此处查看: C ++ 数组的向量


所有版本的标准都允许省略大括号。 - Cubbi
哎呀,GCC 警告真烦人 >.> 我之前不知道这个情况。 - chris
我曾经遇到过同样的问题(现在是2016年),但我用这个语法解决了它:'std::array<int,4> a[] = {1,2,3,4};',所以我用方括号代替了嵌套的花括号。也许有人知道为什么这种变体对我有效? - Sam
6
@Sam,那个意思不同。你发布的语法是创建一个std::array数组的数组(即二维数组),而不是单个数组(即一维数组)。 - Pubby

45
根据 cppreference,只有当省略了=时才需要使用双括号。
// construction uses aggregate initialization
std::array<int, 3> a1{ {1,2,3} };    // double-braces required
std::array<int, 3> a2 = {1, 2, 3}; // except after =
std::array<std::string, 2> a3 = { {std::string("a"), "b"} };

4
只有当你的编译器实现了DR#1270并解除了该限制时,才能这样做。 - Cubbi
@Chubbi 但是为什么它会对“std::array<int, 4> a = {1, 2, 3, 4}”给出警告呢? - Byzantian
4
您可以使用额外的括号轻松满足这个要求。这并不是GCC唯一令人讨厌的警告(您见过“建议在‘||’内部加上‘&&’周围的括号”吗?)。 - Cubbi
你要求警告,所以你得到了它们,但是当然有一种方法可以摆脱它,使用“-Wno-missing-braces”。或者等待GCC 4.8,因为这个std :: array问题,它不包括-Wall中的-Wmissing-braces - Jonathan Wakely
2
警告意味着编译器的作者认为你可能不够聪明,无法正确使用该语言特性。 - Pete Becker
显示剩余2条评论

17

C++17 std::array类模板参数推导(CTAD)

这个新的C++17功能标准库使用,现在允许我们省略模板类型,因此以下内容也可以工作:

main.cpp

#include <array>

int main() {
    std::array a{1, 2, 3};
}

而不是使用std::array<int, 3> a{1, 2, 3};

测试环境:

g++ -ggdb3 -O0 -std=c++17 -Wall -Wextra -pedantic -o main.out main.cpp

如果我们设置-std=c++14,则会编译失败并显示以下错误:

error: missing template arguments before ‘a’

参见:如何推断std::array的大小?

在Ubuntu 18.04,GCC 7.5.0上测试通过。


8

在 CWG 1270 修订前的 C++11 中需要双括号(在修订后的 C++11 和 C++14 及以上版本中不再需要):

// construction uses aggregate initialization
std::array<int, 3> a1{ {1, 2, 3} }; // double-braces required in C++11 prior to the CWG 1270 revision
                                    // (not needed in C++11 after the revision and in C++14 and beyond)
std::array<int, 3> a2 = {1, 2, 3};  // never required after =

std::array 参考文档


-1

我认为你可以简单地使用以下方法:

std::array <int, 6> numbers {0};
numbers[3] = 1;
std::ranges::copy(numbers,  std::ostream_iterator<int>(std::cout, ','));
numbers = {0};
std::cout << "\n";
std::ranges::copy(numbers,  std::ostream_iterator<int>(std::cout, ','));

这如何回答有关初始化的问题?您展示了一个std::array使用示例,但我不明白它在这里的相关性。 - YurkoFlisk
{0}可能不会按照您的预期执行 - 请参见https://godbolt.org/z/EG6v7Gaa1 - ridilculous

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接