初始化时真的需要大括号吗?

时间:2013-12-05 15:42:42

标签: c++ gcc-warning

根据GCC 4.6.3(Ubuntu / Linaro 4.6.3-1ubuntu5)我在以下代码中的数组初始化中缺少大括号:

#include <iostream>
#include <boost/array.hpp>
#include <array>

int main(){
  int                   plain[]   = {1,2,3,4,5};
  std::array  <int, 5>  std_arr   = {1,2,3,4,5}; // warning, see below
  boost::array<int, 5>  boost_arr = {1,2,3,4,5}; // warning, see below
  std::cout << plain[0] << std_arr[1] << boost_arr[2] << std::endl;
}
> g++ test.cc -Wall -Wextra -pedantic --std=c++0x                                                                                  
test.cc: in function »int main()«:
test.cc:7:47: warning: curly braces missing around initialization for »std::array::value_type [5] {aka int [5]}« [-Wmissing-braces]
test.cc:8:47: warning: curly braces missing around initialization for »int [5]« [-Wmissing-braces]

显然(GCC missing braces around initializer)这是GCC中的一个错误,即使在稍微不同的背景下也是如此。答案不同于“提交错误报告”到“只是禁用警告”。

但是,在std::arrayboost::array的情况下,这个警告是多余的,还是我遗漏了一些重要内容?

(我可能会添加额外的括号,而不是禁用警告,但我对这些含义感到好奇)

3 个答案:

答案 0 :(得分:5)

我认为已经回答here

  

std :: array很有趣。它的定义基本上是这样的:

     

template struct std :: array {T a [size]; };

     

它是一个包含数组的结构。它没有构造函数   这需要一个初始化列表。但是std :: array是一个聚合的   C ++ 11的规则,因此可以通过聚合创建   初始化。要聚合初始化struct中的数组,   你需要第二组花括号:

     

std :: array strings = {{“a”,“b”}};

     

请注意,该标准确实表明额外的括号可以   在这种情况下被忽略了。所以它可能是一个GCC错误。

我认为它可能与this defect有关,answer regarding it已在几个问题中联系起来。

这是http://gcc.gnu.org/ml/gcc-patches/2012-03/msg00215.html

  

但是,这些额外的括号可能只能在“宣言中”中删除   形式T x = {a};“(C ++11§8.5.1/ 11),即旧式   =使用。允许括号省略的此规则不适用于直接列表初始化。这里的一个脚注写着:“大括号不能被省略   在列表初始化的其他用途中。“

     

有关此限制的缺陷报告:CWG缺陷   #1270。如果采用提议的解决方案,则允许使用大括号来进行其他形式的列表初始化,...

我注意到错误没有出现在gcc 4.8.1中,但它确实出现在一个非常旧的版本(4.4.7)上,我认为这是补丁(因为提出了缺陷解决方案的日期为2012年2月,此链接的日期为2012年3月):

{{3}}

答案 1 :(得分:3)

这是一个恼人的“安全”警告,它是在早期版本的GCC中为C和C ++聚合初始化器引入的。如果我没记错的话,它早于C ++ 11并且与C ++ 11并不真正相关(同样,它会影响C,因为它会影响C ++)。基本上,在为每个嵌套聚合开始初始化程序时,它需要额外级别的嵌套{}。该语言不需要这个,这就是为什么它只是一个警告。

有问题的警告在许多情况下可能有用,但实施工作却很少考虑。该警告的一个完全荒谬的后果是它用C语言“杀死”= { 0 }初始化者习惯用语。 (在C中,任何东西都可以用= { 0 }初始化,但由于这个恼人的警告,人们不得不选择性地使用诸如= {{0}}= {{{0}}}之类的东西。

在C ++中std::array类是一个聚合,其中= { ... }初始值设定项由旧的内置聚合初始化处理,而不是由专用的构造函数处理。 (在C ++ 11中,聚合初始化的规则是根据初始化列表重写的,但是通过大括号的可能性故意保留了一般的C风格行为。 )因此std::array初始化也会受到该警告的影响。 std::array是包含实际数组的聚合,实际数组也是聚合。因此,为了获取初始化程序中的数组元素,GCC鼓励您打开两个级别的{}

所以,对于std::array,您刚刚找到了另一个例子,说明该警告何时弊大于利。

答案 2 :(得分:2)

不,对于一个简单的类来说,合理的编译器真的没办法解决这个问题。