C++11: Correct std::array initialization?

96,450

Solution 1

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

Solution 2

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"} };

Solution 3

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.

Solution 4

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

Share:
96,450

Related videos on Youtube

Byzantian
Author by

Byzantian

Updated on July 05, 2022

Comments

  • Byzantian
    Byzantian almost 2 years

    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?

    • chris
      chris over 11 years
      std::array is an aggregate. I think they might be making it work with one set in the future, however.
    • Byzantian
      Byzantian over 11 years
      @chris What exactly, do you mean by that?
    • chris
      chris over 11 years
      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.
    • Byzantian
      Byzantian over 11 years
      @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?
    • chris
      chris over 11 years
      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.
    • ildjarn
      ildjarn over 11 years
      @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.
    • Jonathan Wakely
      Jonathan Wakely over 11 years
    • underscore_d
      underscore_d almost 7 years
  • Cubbi
    Cubbi over 11 years
    All versions of the standard allow brace elision.
  • chris
    chris over 11 years
    Huh, stupid GCC warnings >.> I wasn't aware that it was the case already.
  • Cubbi
    Cubbi over 11 years
    @cyberpunk_ only if your compiler implemented DR #1270 which lifts that restriction.
  • Byzantian
    Byzantian over 11 years
    @Chubbi But why does it give me a warning for "std::array<int, 4> a = {1, 2, 3, 4}" then?
  • Cubbi
    Cubbi over 11 years
    @cyberpunk_ It's just a bogus warning.
  • Byzantian
    Byzantian over 11 years
    @Cubbi But annoying nonetheless. There has to be a way to get rid of it.
  • Cubbi
    Cubbi over 11 years
    @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 ‘||’?)
  • Jonathan Wakely
    Jonathan Wakely over 11 years
    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.
  • Pete Becker
    Pete Becker over 11 years
    The warning means that the compiler writer thinks you might not be smart enough to use that language feature correctly.
  • Sam
    Sam almost 8 years
    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?
  • Pubby
    Pubby almost 8 years
    @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).