2

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?
Barry
  • 286,269
  • 29
  • 621
  • 977
101010
  • 41,839
  • 11
  • 94
  • 168
  • 4
    It's a warning; they're both right. GCC also warns with `-Wmissing-braces`. – chris Jun 20 '15 at 23:41
  • 1
    This warning [was disabled by default for later versions of gcc.](http://stackoverflow.com/a/13905432/2388257) – Hi-Angel Jun 21 '15 at 00:43
  • There was a good recap post covering all possible combos of `=`, `{`, `{` etc. but I can't find it now. An annoyance is that `std::array` is not required to use a C-style array internally, so double-braced versions are not correct. – M.M Jun 21 '15 at 04:26

2 Answers2

2

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 ]

Community
  • 1
  • 1
Barry
  • 286,269
  • 29
  • 621
  • 977
0

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.

David G
  • 94,763
  • 41
  • 167
  • 253
  • N3526 was never adopted. Brace elision has been around since C++98; the rules were relaxed somewhat in C++14 by [CWG 1270](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1270), but the code in the OP is valid under either set of rules. – T.C. Jun 21 '15 at 01:16
  • @T.C. I assumed it was adopted because we obviously have this in C++14. Why would that proposal be rejected but the cwg issue be considered? – David G Jun 21 '15 at 01:51
  • No, you don't have what that paper is proposing, in C++14 or otherwise. (`std::array a = { {1}, {2} };` is an error.) – T.C. Jun 21 '15 at 01:55