【问题标题】:Are curly braces really required around initialization?初始化时真的需要花括号吗?
【发布时间】:2013-12-05 15:42:42
【问题描述】:

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

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

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

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

【问题讨论】:

  • 这是一个警告。如果它是“必需的”,那将是一个错误。
  • 不应该是std::array&lt;int,5} arr{1,2,3,4,5};吗? (未选中)
  • @Alex 不,但std::array&lt;int,5&gt; arr{1,2,3,4,5}; 是合法的。
  • @Alex 允许使用 =。 @Zeta 两个大括号是“必需的”,因为数组本身是一个带有内部 C 数组(第二对大括号)的结构(一对大括号)。在这种情况下,标准允许您省略第二对。
  • @Malloc:假设 CWG1270 是固定的。否则还是std::array&lt;int,5&gt; arr{{1,2,3,4,5}};

标签: c++ gcc-warning


【解决方案1】:

我想这已经回答了here

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

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

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

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

请注意,标准确实建议额外的大括号可以是 在这种情况下被省略。所以它可能是一个 GCC 错误。

我相信它可能与this defect有关,它已在多个问题中链接。

这是answer regarding it

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

有关于此限制的缺陷报告:CWG 缺陷 #1270.如果提议的解决方案被采纳,其他形式的列表初始化将允许大括号省略,...

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

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

【讨论】:

  • 请注意,给出的示例是T x = { a }; 形式。所以只有最后一个报价适用。 CWG 1270 涵盖其他情况,例如Alex 中对问题的评论。
  • @remyabel:您引用的“有用的评论”暗示聚合类初始化和内置数组初始化之间存在概念差异。似乎暗示聚合类由“经典”聚合初始化处理,而数组初始化是一个新的“初始化器列表”初始化。这种区别真的存在于 C++11 中吗?在 C++03 和之前,数组是聚合的,这意味着一切都由聚合初始化统一处理。
【解决方案2】:

这是一个令人讨厌的“安全”警告,它是在早期版本的 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,您刚刚发现了另一个示例,说明该警告何时弊大于利。

【讨论】:

    【解决方案3】:

    不,对于这么简单的类,一个合理的编译器确实无法搞砸。

    【讨论】:

    • 我希望一个合理的编译器会抱怨不符合标准的代码,这会发生在这里。我明白你的意思,但不知何故允许这样做感觉真的不对。
    猜你喜欢
    • 2017-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多