90

If I initialize a std::array as follows, the compiler gives me a warning about missing braces

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

This fixes the problem:

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

This is the warning message:

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

Is this just a bug in my version of gcc, or is it done intentionally? If so, why?

Amit G.
  • 2,546
  • 2
  • 22
  • 30
Byzantian
  • 3,208
  • 4
  • 27
  • 31
  • 3
    `std::array` is an aggregate. I think they might be making it work with one set in the future, however. – chris Jan 06 '13 at 01:12
  • 1
    @chris What exactly, do you mean by that? – Byzantian Jan 06 '13 at 01:13
  • 5
    Well, you know how you can have `struct S {int i; int j;};` and initialize it using `S s = {5, 6};`? That's aggregate initialization. `std::array` contains a built-in array, which can be initialized via an initializer list, which is what the inner set is. The outer set is for aggregate initialization. – chris Jan 06 '13 at 01:14
  • @chris So in my case "{1, 2, 3, 4}" is just a std::initializer_list object which itself has to be placed within the actual initialization braces? – Byzantian Jan 06 '13 at 01:17
  • Well, I'm not overly sure of how built-in array initializer lists are handled after the introduction of that type, but that's the gist of it, yes. One's for the class, and the other is for the array inside the class. – chris Jan 06 '13 at 01:23
  • @cyberpunk_ : A C-array is an aggregate by definition. Given that `std::array<>` is an aggreate also, the first brace initializes the `std::arrat<>`, and the second initializes the inner C-array. – ildjarn Jan 06 '13 at 04:22
  • dup http://stackoverflow.com/q/8863319/981959 dup http://stackoverflow.com/q/11400090/981959 – Jonathan Wakely Jan 06 '13 at 15:08
  • Possible duplicate of [When can outer braces be omitted in an initializer list?](https://stackoverflow.com/questions/11734861/when-can-outer-braces-be-omitted-in-an-initializer-list) – underscore_d Jul 23 '17 at 09:32

5 Answers5

61

This is the bare implementation of std::array:

template<typename T, std::size_t N>
struct array {
    T __array_impl[N];
};

It's an aggregate struct whose only data member is a traditional array, such that the inner {} is used to initialize the inner array.

Brace elision is allowed in certain cases with aggregate initialization (but usually not recommended) and so only one brace can be used in this case. See here: C++ vector of arrays

Community
  • 1
  • 1
Pubby
  • 51,882
  • 13
  • 139
  • 180
  • All versions of the standard allow brace elision. – Cubbi Jan 06 '13 at 01:15
  • Huh, stupid GCC warnings >.> I wasn't aware that it was the case already. – chris Jan 06 '13 at 01:20
  • I had the same problem (2016 by now), but I fixed it with this syntax: 'std::array a[] = {1,2,3,4};' So I added square braces instead of nested curly braces. Maybe someone knows why this variant worked for me? – Sam May 31 '16 at 20:50
  • 6
    @Sam That has a different meaning. The syntax you posted is creating an array of std::arrays (a 2-dimensional array), rather than a single array (1-dimensional). – Pubby Jun 01 '16 at 12:45
44

According to cppreference. Double braces are required only if = is omitted.

// 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"} };
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Draco Ater
  • 20,820
  • 8
  • 62
  • 86
  • 4
    @cyberpunk_ only if your compiler implemented [DR #1270](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1270) which lifts that restriction. – Cubbi Jan 06 '13 at 01:21
  • @Chubbi But why does it give me a warning for "std::array a = {1, 2, 3, 4}" then? – Byzantian Jan 06 '13 at 01:26
  • @cyberpunk_ It's just a bogus warning. – Cubbi Jan 06 '13 at 01:27
  • @Cubbi But annoying nonetheless. There has to be a way to get rid of it. – Byzantian Jan 06 '13 at 01:31
  • 4
    @cyberpunk_ You can trivially satisfy it with the extra braces. It's not the only annoying warning GCC has (ever seen `suggest parentheses around ‘&&’ within ‘||’`?) – Cubbi Jan 06 '13 at 01:34
  • You asked for warnings so you got them, but of course there's a way to get rid of it, use `-Wno-missing-braces`. Or wait for GCC 4.8 which doesn't include `-Wmissing-braces` in `-Wall` because of this `std::array` issue. – Jonathan Wakely Jan 06 '13 at 15:04
  • 2
    The warning means that the compiler writer thinks you might not be smart enough to use that language feature correctly. – Pete Becker Jan 06 '13 at 17:33
16

C++17 std::array class template argument deduction (CTAD)

This new C++17 feature is used by the standard library and now allows us to omit the template types as well so that the following works:

main.cpp

#include <array>

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

instead of std::array<int, 3> a{1, 2, 3};

Tested with:

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

If we set -std=c++14 instead for example, it fails to compile with:

error: missing template arguments before ‘a’

See also: Deduce std::array size?

Tested on Ubuntu 18.04, GCC 7.5.0.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
7

Double-braces required in C++11 prior to the CWG 1270 (not needed in C++11 after the revision and in C++14 and beyond):

// 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 reference

Amit G.
  • 2,546
  • 2
  • 22
  • 30
0

I think you can simply use the following,

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, ','));