当我聚合初始化数组时,Clang警告我,而gcc没有

时间:2015-06-20 23:39:44

标签: c++ c++11 gcc clang stdarray

当我使用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-括号]

CLANG DEMO

但是,GCC编写此程序时根本没有发出警告。

GCC DEMO

问:

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

2 个答案:

答案 0 :(得分:2)

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

来自[dcl.init.aggr]:

  

可以在初始化列表中省略大括号,如下所示。如果初始化列表以左括号开头,那么   初始化子句的后续逗号分隔列表初始化子聚合的成员;它是   错误的是 initializer-clauses 比成员更多。但是,如果是子集合的初始化列表   不会以左括号开头,然后只有足够的 initializer-clause 从列表中获取   初始化子集合的成员;任何剩余的初始化程序 - 子句都会留下来初始化下一个   当前子聚合为成员的聚合成员。 [例如:

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]个元素被初始化,就像使用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]

答案 1 :(得分:0)

  

哪种编译器是对的?

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

  

Clangs警告我的原因是什么?

Clang通过警告你是有帮助的,因为虽然你能够忽略大括号,但是如果你不小心的话,也不总是清楚如何初始化聚合。您必须确定哪些初始化子句与哪些成员子对象有关。