7

How to initialize a nested (2D) std::array via an initializer-list?

template <std::size_t W, std::size_t H>
class Block
{
    std::array<std::array<int, W>, H> block;
public:

    template <typename ...E>
    Block(E&&...e) : block {{std::forward<E>(e)...}} {}
};

The class Block should able to initialize block member as below:

Block<3, 2> b {{ {1, 2, 3}, {4, 5, 6} }};

Note: We have the ability to initialize the std::array directly in C++11:

std::array<std::array<int, 3>, 2> b {{ {1, 2, 3}, {4, 5, 6} }};

I'm using gcc-4.9.0

masoud
  • 55,379
  • 16
  • 141
  • 208
  • By making `block` private and providing a ctor, `Block` now isn't an aggregate any more. As braced-initializers are never deduced from, the only valid initialized for an object of type `Block<3,2>` now is `Block<3,2> b {1,2,3,4,5,6}` – dyp Nov 03 '13 at 21:56
  • Roll this back to the revision that makes sense for the answers, then ask a new question. – Shog9 Nov 12 '13 at 03:39

2 Answers2

6

The rules for braces are very complicated when it comes to nested structures.

The simplest form in your code would be this:

Block<3, 2> b {1, 2, 3, 4, 5, 6};

That basically omits all the inner braces — these omissions are allowed by the language.

The next syntax, which is slightly complex, is this:

Block<3, 2> b {{1, 2, 3, 4, 5, 6}};

It still omits braces, but as far as Block and as its member is concerned it is FULLY braced. It omits braces for the array and its members.

And this one is FULLY braced:

Block<3, 2> b {{{ {{1, 2,3}}, {{4,5,6}} }}}; 

It braces for all inner structures.

All forms compiles fine.

See my other answer for detailed explanation:

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
1

It may be to do with the interpretation of the standard being overly capricious with the number of braces required to initialize std::array. This fully braced version compiles without issues on GCC 4.8.1:

Block<3, 2> b {
               {
                { 
                 { {1, 2, 3} }, { {4, 5, 6} } 
                }
               }
              }; 

Strangely, this version compiles too:

  Block<3, 2> b { 
                 {{ {1, 2, 3}, {4, 5, 6} } }
                };
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • 1
    @MM. No problem. It still doesn't make any sense to me. Anyway, I think your first attempt should be legal in C++14. – juanchopanza Nov 03 '13 at 19:32