2

当我用 CLANG 编译以下代码时:

#include <iostream>
#include <array>
#include <algorithm>
#include <functional>

int main() {
  std::array<int, 2> a = {1, 2};
  std::array<int, 2> b = {2, 1};
  std::array<int, 2> c;
  std::transform(a.begin(), a.end(), b.begin(), c.begin(), std::multiplies<int>());
  for(auto &&i : c) std::cout << i << " ";
  std::cout << std::endl;
}

通过发出命令:

clang++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp

它发出警告:

警告:建议在子对象初始化时使用大括号 [-Wmissing-braces]

铿锵演示

但是,GCC 编译该程序时根本不会发出警告。

海合会演示

问:

  1. 哪个编译器是对的?
  2. Clangs警告我的原因是什么?
4

2 回答 2

2

在某些情况下,可以省略大括号。这是其中一种情况。用于初始化的最外层大括号ab可选的。无论哪种方式,它在语法上都是正确的 - 但只包含它们会更清楚。Clang 只是警告你(警告,而不是错误) - 这是一个完全有效的警告。正如chris指出的那样,-Wmissing-bracesgcc 会发出相同的警告。最终,两个编译器都接受了代码,这是正确的;毕竟,它是一个有效的程序。这才是最重要的。

来自 [dcl.init.aggr]:

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

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

是一个完全支撑的初始化:135初始化数组 的第一行y[0],即y[0][0]y[0][1]y[0][2]。同样,接下来的两行初始化y[1]y[2]。初始化程序提前结束,因此y[3]s 元素被初始化,就好像用 形式的表达式显式初始化一样float(),即用 初始化0.0。在下面的例子中,初始化列表中的大括号被省略了;但是初始化器列表与上面示例的完全支撑初始化器列表具有相同的效果,

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

for 的初始化程序y以左大括号开头,但 fory[0]没有,因此使用列表中的三个元素。同样,接下来的三个依次为y[1]y[2]—结束示例]

于 2015-06-20T23:51:34.477 回答
0

哪个编译器是对的?

两个编译器都是正确的。Brace-elision是一项允许聚合由一对大括号初始化的功能。每个成员子对象都根据需要使用尽可能多的初始化子句进行初始化。这是为了允许更方便的初始化形式。

Clangs警告我的原因是什么?

Clang 通过警告你很有帮助,因为虽然你可以省略大括号,但如果你不小心,聚合将如何初始化并不总是很清楚。您必须确定哪些初始化子句与哪些成员子对象相关。

于 2015-06-20T23:57:42.590 回答