何时可以在初始值列表中省略外括号? [英] When can outer braces be omitted in an initializer list?

查看:114
本文介绍了何时可以在初始值列表中省略外括号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在编译下面的代码时,我在VC2010中遇到错误C2078。

  struct A 
{
int foo;
double bar;
};

std :: array< A,2> a1 =
//错误C2078:初始化程序太多
{
{0,0.1},
{2,3.4}
}

// OK
std :: array< double,2> a2 = {0.1,2.3};

我发现 a1

  std :: array< A,2& a1 = 
{{
{0,0.1},
{2,3.4}
}};

问题是: a1 但不需要 a2



更新 b
$ b

问题似乎不是std :: array特有的。一些示例:

  struct B 
{
int foo [2];
};

// OK
B meow1 = {1,2};
B bark1 = {{1,2}};

struct C
{
struct
{
int a,b;
} foo;
};

// OK
C meow2 = {1.2};
C bark2 = {{1,2}};

struct D
{
struct
{
int a,b;
} foo [2];
};

D meow3 = {{1,2},{3,4}}; //错误C2078:初始化器太多
D bark3 = {{{1,2},{3,4}}};

我还是不明白为什么 struct D

需要额外的大括号,因为 std :: array 是一个聚合和POD,不同于标准库中的其他容器。 std :: array 没有用户定义的构造函数。它的第一个数据成员是一个大小为 N (你作为模板参数传递)的数组,这个成员直接用initializer初始化。



情况与以下情况相同:

  //定义这个聚合 - 没有用户定义的构造函数
struct Aarray
{
A data [2] // data是一个内部数组!
};

如何初始化?如果您这样做:

  Aarray a1 = 
{
{0,0.1},
{2,3.4}
};

它会导致编译错误


错误:'Aarray'的初始化设置太多


这也是 std :: array 情况下得到的相同的错误(如果你使用GCC) !



因此,正确的使用方式是使用大括号:

  Aarray a1 = 
{
{//< - 这告诉编译器'data'的初始化开始了!

{//< - 初始化`data [0]`开始!

0,0.1

},// < - 初始化`data [0]`结束

{2,3.4} /初始化数据[1]开始和结束,如上所述!

} //< - 这告诉编译器`data`的初始化结束了!
};

编译< a>。再次需要额外的大括号,因为您正在初始化内部数组。



-



现在的问题是,为什么在 double 的情况下不需要额外的大括号?



这是因为 double 不是一个聚合,而 code> is。换句话说, std :: array< double,2> 是聚合的聚合,而 std :: array< A,2& code>是汇总 1 的汇总。



1。我认为在双重情况下(例如这个)还需要额外的大括号,以完全是标准符合性,但它没有它。看来我需要再次挖掘规范!。



更多括号和额外大括号



本节(C ++ 11中的§8.5.1/ 11)很有趣,适用于这种情况:


形式



T x = {a};



大括号可以在初始化列表中省略,如下所示。如果初始化器列表以左大括号开头,则以逗号分隔的初始化子句的后续列表初始化子集合的成员;它是错误的有更多的初始化子句而不是成员。然而,如果子聚集
的初始化器列表不以左大括号开始,则仅从列表中获得足够的初始化子句来初始化子聚集的成员;任何剩余的初始化子句将留下来初始化当前子聚集是其成员的聚合的下一个成员。 [示例:



float y [4] [3] = {
{1,3,5},
{2,4,6},
{3,5,7},
};



完全支持的初始化:1,3和5初始化数组 y [0] 的第一行,即 y [0] [0] y [0] [1] y [0] 。同样,接下来的两行初始化 y [1] y [2] 。初始化器提前结束,因此 y [3] s 元素被初始化为使用形式为float()的表达式显式初始化,即使用0.0初始化。在下面的示例中,初始化器列表中的大括号被省略;但是initializer-list具有与上面示例的完全支持的初始化器列表相同的效果。



float y [4] [3 ] = {
1,3,5,2,4,6,3,5,7
};



y的初始化器以左括号开始,但 y [0] 的初始化器不会,因此使用列表中的三个元素。同样,接下来的三个依次为 y [1] y [2] 。 -end example]


根据我从上面的引用我的理解,我可以说应该允许以下内容:

  // OKAY。大括号完全消失了内聚集! 
std :: array< A,2> X =
{
0,0.1,
2,3.4
};

// OKAY。完全支持的初始化!
std :: array< A,2> Y =
{{
{0,0.1},
{2,3.4}
}};

在第一个大括号内部聚合完全消除,而第二个是完全支撑初始化。在你的情况下( double 的情况下),初始化使用第一种方法(大括号完全用于内部聚合) p>

但不允许这样做:

  // ILL- FORMED:it是不是! 
std :: array< A,2> Z =
{
{0,0.1},
{2,3.4}
};

它既不支持大括号,也没有足够的大括号来完全支持初始化。因此,这是一个错误的!


I've got error C2078 in VC2010 when compiling the code below.

struct A
  {
  int foo;
  double bar;
  };

std::array<A, 2> a1 = 
  // error C2078: too many initializers
  {
    {0, 0.1},
    {2, 3.4}
  };

// OK
std::array<double, 2> a2 = {0.1, 2.3};

I found out that the correct syntax for a1 is

std::array<A, 2> a1 = 
  {{
    {0, 0.1},
    {2, 3.4}
  }};

The question is: why extra braces are required for a1 but not required for a2?

Update

The question seems to be not specific to std::array. Some examples:

struct B
  {
  int foo[2];
  };

// OK
B meow1 = {1,2};
B bark1 = {{1,2}};

struct C
  {
  struct 
    { 
    int a, b; 
    } foo;
  };

// OK
C meow2 = {1,2};
C bark2 = {{1,2}};

struct D
  {
  struct 
    { 
    int a, b; 
    } foo[2];
  };

D meow3 = {{1,2},{3,4}};  // error C2078: too many initializers
D bark3 = {{{1,2},{3,4}}};

I still don't see why struct D gives the error but B and C don't.

解决方案

The extra braces is needed because std::array is an aggregate and POD, unlike other containers in the standard library. std::array doesn't have user-defined constructor. It's first data member is an array of size N (which you pass as template argument), and this member is directly initialized with initializer. The extra braces is needed for the internal array which is directly being initialized.

The situation is same as:

//define this aggregate - no user-defined constructor
struct Aarray
{
   A data[2];  //data is an internal array!
};

How would initialize this? If you do this:

Aarray a1 =
{
   {0, 0.1},
   {2, 3.4}
};

it gives compilation error:

error: too many initializers for 'Aarray'

It is the same error which you get in case of std::array also (if you use GCC)!

So the correct way use is to use braces as:

Aarray a1 =
{
  {  //<--this tells the compiler that initialization of `data` starts!

        { //<-- initialization of `data[0]` starts!

           0, 0.1

        }, //<-- initialization of `data[0]` ends

       {2, 3.4}  //initialization of data[1] starts and ends, as above!

  } //<--this tells the compiler that initialization of `data` ends!
};

which compiles fine. Once again the extra braces is needed because you're initializing the internal array.

--

Now the question is, why extra braces is not needed in case of double?

It is because double is not an aggregate, while A is. In other words, std::array<double, 2> is an aggregate of aggregate, while std::array<A, 2> is an aggregate of aggregate of aggregate1.

1. I think that extra braces is still needed in case of double also (like this), to be completely the Standard conformant, but it works without it. It seems I need to dig the spec again!.

More on braces and extra braces

I dig the spec. This section (§8.5.1/11 from C++11) is interesting and applies to this case:

In a declaration of the form

T x = { a };

braces can be elided in an initializer-list as follows. If the initializer-list begins with a left brace, then the succeeding comma-separated list of initializer-clauses initializes the members of a subaggregate; it is erroneous for there to be more initializer-clauses than members. If, however, the initializer-list for a subaggregate does not begin with a left brace, then only enough initializer-clauses from the list are taken to initialize the members of the subaggregate; any remaining initializer-clauses are left to initialize the next member of the aggregate of which the current subaggregate is a member. [ Example:

float y[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 }, };

is a completely-braced initialization: 1, 3, and 5 initialize the first row of the array y[0], namely y[0][0], y[0][1], and y[0][2]. Likewise the next two lines initialize y[1] and y[2]. The initializer ends early and therefore y[3]s elements are initialized as if explicitly initialized with an expression of the form float(), that is, are initialized with 0.0. In the following example, braces in the initializer-list are elided; however the initializer-list has the same effect as the completely-braced initializer-list of the above example,

float y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };

The initializer for y begins with a left brace, but the one for y[0] does not, therefore three elements from the list are used. Likewise the next three are taken successively for y[1] and y[2]. —end example ]

Based on what I understood from the above quote, I can say that the following should be allowed:

//OKAY. Braces are completely elided for the inner-aggregate!
std::array<A, 2> X =   
{
  0, 0.1,
  2, 3.4
};

//OKAY. Completely-braced initialization!
std::array<A, 2> Y = 
{{
   {0, 0.1},
   {2, 3.4}
}};

In the first one braces for inner-aggregate are completely-elided, while the second is completely-braced initialization. In your case (the case of double), the initialization uses the first approach (braces are completely elided for the inner aggregate!).

But this should be disallowed:

//ILL-FORMED : it is neither!
std::array<A, 2> Z = 
{
  {0, 0.1},
  {2, 3.4}
};

It is neither braces-elided, nor are there enough braces to be completely-braced initialization. Therefore, it is an ill-formed!

这篇关于何时可以在初始值列表中省略外括号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆