C++11: Correct std::array initialization?
Asked Answered
A

5

95

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?

Amphicoelous answered 6/1, 2013 at 1:10 Comment(8)
std::array is an aggregate. I think they might be making it work with one set in the future, however.Coercive
@Coercive What exactly, do you mean by that?Amphicoelous
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.Coercive
@Coercive 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?Amphicoelous
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.Coercive
@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.Flatt
dup https://mcmap.net/q/225159/-std-array-lt-t-gt-initialization/981959 dup https://mcmap.net/q/162632/-why-is-the-c-initializer_list-behavior-for-std-vector-and-std-array-different/981959Yongyoni
Possible duplicate of When can outer braces be omitted in an initializer list?Porphyria
I
66

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

Interdental answered 6/1, 2013 at 1:13 Comment(4)
All versions of the standard allow brace elision.Megalopolis
Huh, stupid GCC warnings >.> I wasn't aware that it was the case already.Coercive
I had the same problem (2016 by now), but I fixed it with this syntax: 'std::array<int,4> a[] = {1,2,3,4};' So I added square braces instead of nested curly braces. Maybe someone knows why this variant worked for me?Lycanthrope
@Lycanthrope 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).Interdental
I
47

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"} };
Ice answered 6/1, 2013 at 1:17 Comment(7)
@cyberpunk_ only if your compiler implemented DR #1270 which lifts that restriction.Megalopolis
@Chubbi But why does it give me a warning for "std::array<int, 4> a = {1, 2, 3, 4}" then?Amphicoelous
@cyberpunk_ It's just a bogus warning.Megalopolis
@Megalopolis But annoying nonetheless. There has to be a way to get rid of it.Amphicoelous
@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 ‘||’?)Megalopolis
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.Yongyoni
The warning means that the compiler writer thinks you might not be smart enough to use that language feature correctly.Paraphrast
A
18

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.

Amadoamador answered 22/4, 2020 at 17:24 Comment(0)
R
8

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

Raffish answered 28/7, 2018 at 3:16 Comment(0)
R
-2

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, ','));
Richelle answered 21/7, 2022 at 21:22 Comment(2)
How does this answer the question about initialization? You display an example of std::array usage, but I don't see how it is relevant here.Morales
{0} might not do what you expect - see godbolt.org/z/EG6v7Gaa1Octan

© 2022 - 2024 — McMap. All rights reserved.