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

Are curly braces really required around initialization?

本文关键字:真的 初始化      更新时间:2023-10-16

根据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++0xtest.cc:在函数中»int main()«:test.cc:7:47:警告:初始化»std::array::value_type[5]{aka int[5]}«[-Wmissing braces]时缺少大括号test.cc:8:47:警告:初始化»int[5]«[-Wmissing brackets]
时缺少大括号

显然(GCC在初始值设定项周围缺少大括号)这是GCC中的一个错误,即使在稍微不同的上下文中也是如此。答案不同于"提交错误报告"answers"仅禁用警告"。

然而,在std::arrayboost::array的上下文中,这个警告是多余的,还是我遗漏了一些重要的东西?

(我可能会添加额外的大括号,而不是禁用警告,但我很好奇其含义)

我想这里已经回答了这个问题。

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

模板结构std::数组{T a〔size〕;};

它是一个包含数组的结构。它没有构造函数需要一个初始值设定项列表。但是std::array是C++11的规则,因此它可以通过聚合创建初始化。为了聚合初始化结构内部的数组,你需要第二套大括号:

std::array字符串={{"a","b"}};

请注意,该标准确实建议额外的支架可以在这种情况下被忽略。所以它很可能是一个GCC错误。

我相信这可能与这个缺陷有关,这个缺陷在几个问题上都有联系。

以下是关于它的答案:

然而,这些额外的大括号只能在形式T x={a};"(C++11§8.5.1/11),即当使用=。此允许省略大括号的规则不适用于直接列表初始化。这里的脚注写道:"括号不能省略在列表初始化的其他用途中。"

有一份关于该限制的缺陷报告:CWG缺陷#1270.如果所提出的决议获得通过,将允许对其他形式的列表初始化省略大括号。。。

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

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

这是一个烦人的"安全"警告,它是在早期版本的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,您刚刚发现了另一个警告弊大于利的例子。

不,对于一个如此简单的类,一个合理的编译器真的不可能把它搞砸。