用初始化列表来初始化2D std::array成员

7
如何通过初始化列表初始化嵌套(2D)std::array
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)...}} {}
};

Block应该能够如下初始化其成员变量block

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

注意:在 C++11 中,我们有能力直接初始化 std::array
std::array<std::array<int, 3>, 2> b {{ {1, 2, 3}, {4, 5, 6} }};

我正在使用gcc-4.9.0


通过将block设为私有,同时提供一个构造函数,Block现在不再是聚合了。由于大括号初始化器永远不会被自动推导出来,因此类型为Block<3,2>的对象唯一有效的初始化方式是 Block<3,2> b {1,2,3,4,5,6} - dyp
将此回滚到对答案有意义的版本,然后提出一个新问题。 - Shog9
2个回答

6
对于嵌套结构,花括号的规则非常复杂。
在你的代码中,最简单的形式是这样的:
Block<3, 2> b {1, 2, 3, 4, 5, 6};

基本上,这省略了所有内部括号 - 这些省略是语言允许的。
下一个语法稍微复杂,如下:
Block<3, 2> b {{1, 2, 3, 4, 5, 6}};

这段代码仍然省略了花括号,但是就Block及其成员而言,它已经完全使用了花括号。对于array及其成员,它省略了花括号。

而这一段则完全使用了花括号:

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

它支撑所有内部结构。

所有表单都编译良好

详细解释请参见我的其他回答:


1
这可能与标准的解释过于挑剔有关,需要使用大括号来初始化std::array。在GCC 4.8.1上,这个完全带有大括号的版本可以编译通过:
Block<3, 2> b {
               {
                { 
                 { {1, 2, 3} }, { {4, 5, 6} } 
                }
               }
              }; 

奇怪的是,这个版本也可以编译:


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

1
@MM。没问题。但我还是不太明白。无论如何,我认为你的第一次尝试在C++14中是合法的。 - juanchopanza

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