Clang warns me when I aggregate initialize an arra

2019-07-09 03:40发布

问题:

When I compile the following piece of code with 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;
}

by issuing the command:

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

It issues the warning:

warning: suggest braces around initialization of subobject [-Wmissing-braces]

CLANG DEMO

However, GCC compiles this program with out issuing a warning at all.

GCC DEMO

Q:

  1. Which compiler is right?
  2. What's the reason that Clangs warns me?

回答1:

In some cases, braces can be elided. This is one of those cases. The outer-most braces for initializing a and b are optional. It is syntactically correct either way - but it's clearer to just include them. Clang is just warning you (warning, not error) about this - it's a perfectly valid warning. And as chris, points out, with -Wmissing-braces, gcc issues the same warning. Ultimately, both compilers accept the code, which is correct; it is, after all, a valid program. That's all that matters.

From [dcl.init.aggr]:

Braces can be elided in an initializer-list as follows. If the initializer-list begins with a left brace, then the succeeding comma-separated list of initializer-clauses initializes the members of a subaggregate; it is erroneous for there to be more initializer-clauses than members. If, however, the initializer-list for a subaggregate does not begin with a left brace, then only enough initializer-clauses from the list are taken to initialize the members of the subaggregate; any remaining initializer-clauses are left to initialize the next member of the aggregate of which the current subaggregate is a member. [ Example:

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

is a completely-braced initialization: 1, 3, and 5 initialize the first row of the array y[0], namely y[0][0], y[0][1], and y[0][2]. Likewise the next two lines initialize y[1] and y[2]. The initializer ends early and therefore y[3]s elements are initialized as if explicitly initialized with an expression of the form float(), that is, are initialized with 0.0. In the following example, braces in the initializer-list are elided; however the initializer-list has the same effect as the completely-braced initializer-list of the above example,

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

The initializer for y begins with a left brace, but the one for y[0] does not, therefore three elements from the list are used. Likewise the next three are taken successively for y[1] and y[2]. —end example ]



回答2:

Which compiler is right?

Both compilers are right. Brace-elision is a feature that allows an aggregate to be initialized by a single pair of braces. Each member suboject is initialized with as many initializer-clauses as necessary. This is to allow a more convenient form of initialization.

What's the reason that Clangs warns me?

Clang is being helpful by warning you because while you are able to elide the braces, it isn't always clear how the aggregate will be initialized if you aren't careful. You have to be certain which initializer-clauses pertain to which member subobjects.