6

According to GCC 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) I'm missing a curly brace in the array initialization in the following code:

#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: in function »int main()«:
test.cc:7:47: warning: curly braces missing around initialization for »std::array::value_type [5] {aka int [5]}« [-Wmissing-braces]
test.cc:8:47: warning: curly braces missing around initialization for »int [5]« [-Wmissing-braces]

Apparently (GCC missing braces around initializer) this is a bug in GCC, even in a slightly different context. The answers differ from "file a bug report" to "just disable the warning".

However, in the context of std::array or boost::array, is this warning superfluous, or am I missing something important?

(I will probably add the additional braces instead of disabling the warning, but I'm curious about the implications)

Community
  • 1
  • 1
Zeta
  • 103,620
  • 13
  • 194
  • 236
  • 1
    It's a warning. If it was "required", it would be an error. – Wooble Dec 05 '13 at 15:47
  • shouldn't it be `std::array – Alexander Oh Dec 05 '13 at 15:56
  • @Alex No, but `std::array arr{1,2,3,4,5};` would be legal. – Baum mit Augen Dec 05 '13 at 16:09
  • 1
    @Alex the `=` is allowed. @Zeta Two braces are "required" because the array itself is a struct (one pair of braces) with an internal C array (second pair of braces). You are allowed by the standard to omit the second pair in this circumstance. – Simple Dec 05 '13 at 16:14
  • @Malloc: Assuming CWG1270 is fixed. Otherwise it's still `std::array arr{{1,2,3,4,5}};` – MSalters Dec 05 '13 at 16:21
  • @Wooble - not necessarily. For invalid code, the language definition requires "a diagnostic"; once the compiler issues a diagnostic, it's free to continue to compile the code, giving it an implementation-specific meaning. That's the hook for implementation-specific extensions. – Pete Becker Dec 05 '13 at 16:28
  • @Simple: Doh. Totally forgot about that. See, that's what I was talking about when I said _"missing something important" (or trivial)_ :D. – Zeta Dec 05 '13 at 17:54

3 Answers3

4

I think this is already answered here.

std::array is funny. It is defined basically like this:

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

It is a struct which contains an array. It does not have a constructor that takes an initializer list. But std::array is an aggregate by the rules of C++11, and therefore it can be created by aggregate initialization. To aggregate initialize the array inside the struct, you need a second set of curly braces:

std::array strings = {{ "a", "b" }};

Note that the standard does suggest that the extra braces can be elided in this case. So it likely is a GCC bug.

I believe it might be related to this defect, which has been linked in several questions.

Here's an answer regarding it:

However, these extra braces may only be elided "in a declaration of the form T x = { a };" (C++11 §8.5.1/11), that is, when the old style = is used . This rule allowing brace elision does not apply for direct list initialization. A footnote here reads: "Braces cannot be elided in other uses of list-initialization."

There is a defect report concerning this restriction: CWG defect #1270. If the proposed resolution is adopted, brace elision will be allowed for other forms of list initialization, ...

I noticed that the error does not appear in gcc 4.8.1, but it does on a very old version (4.4.7), and I think this is the patch (because the defect proposed solution is dated Feb 2012, and this link is dated Mar 2012):

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

Community
  • 1
  • 1
  • Note that the example given is of the `T x = { a };` form. So only the last quote applies. CWG 1270 covers other cases, e.g. the one in Alex'comment on the question. – MSalters Dec 05 '13 at 16:20
  • @remyabel: The "helpful comment" you quoted implies that there's conceptual difference between aggregate class initialization and built-in array initialization. It seems to imply that aggregate class is handled by "classic" aggregate initialization, while array initialization is a new "initializer list" initialization. Does this distinction really exist in C++11? In C++03 and before arrays were aggregates, meaning that everything was handled uniformly by aggregate initialization. – AnT stands with Russia Dec 05 '13 at 16:57
3

It is an annoying "safety" warning that was introduced in one of the earlier versions of GCC for both C and C++ aggregate initializers. If I remember correctly, it predates C++11 and is not really related to C++11 (again, it affects C as much as it affects C++). Basically, it requires an additional level of nested {} when beginning an initializer for each nested aggregate. The language does not require this, which is why it is just a warning.

The warning in question could be useful in many cases, but the implementation was poorly thought through. One completely preposterous consequence of that warning is that it "kills" the = { 0 } initializer idiom in C language. (In C anything can be initialized with = { 0 }, but because of this annoying warning one is forced to selectively use things like = {{0}}, = {{{0}}} and such).

In C++ std::array class is an aggregate, for which = { ... } initializers are handled by the good-old built-in aggregate initialization, not by a dedicated constructor. (In C++11 the rules of aggregate initialization were rewritten in terms of initializer lists, but the general C-style behavior was intentionally preserved through the possibility of brace elision.) For this reason std::array initialization is also affected by that warning. std::array is an aggregate containing the actual array, which is also an aggregate. For this reason, in order to get to the array elements in the initializer GCC encourages you to open two levels of {}.

So, with std::array you just found another example of when that warning does more harm than good.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
2

No, there's really no way in which a reasonable compiler can screw this up, for a class this simple.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • I would expect a reasonable compiler to complain about non-conforming code and this happens here. I see your point, but allowing this feels really wrong somehow. – pmr Dec 05 '13 at 16:23