Why can I initialize a regular array from {}, but not a std::array

懵懂的女人 提交于 2019-12-05 03:01:55

There are two issues one which is a matter of style and the warning.

Although it may not be obvious, aggregate initialization is happening on a temporary which is then being used as an argument to the copy constructor. The more idiomatic to do this initialization would be as follows:

std::array<int, 10> arr = {}; 

Although this still leaves the warning.

The warning is covered by gcc bug report: - -Wmissing-field-initializers relaxation request and one of the comments says:

[...]Surely, the C++ syntax of saying MyType x = {}; should be supported, as seen here:

http://en.cppreference.com/w/cpp/language/aggregate_initialization

where for instance:

struct S {
  int a;
  float b;
  std::string str;
};

S s = {}; // identical to S s = {0, 0.0, std::string};

That shouldn't warn for the reasons stated in earlier comments.

and a follow-up comment says:

My statement about zero-initialization was inaccurate (thanks), but the general point still stands: in C you have to write ' = {0}' since empty-braces initializer is not supported by the language (you get a warning with -pedantic); in C++, you can write ' = {}' or 'T foo = T();', but you don't need to write ' = {0}' specifically.

The latest versions of gcc does not produce this warning for this case, see it live working with gcc 5.1.

We can see this topic also covered in the Clang Developers lists in the thead: -Wmissing-field-initializers.

For reference the draft C++11 standard section 8.5.1 [dcl.init.aggr] says:

If there are fewer initializer-clauses in the list than there are members in the aggregate, then each member not explicitly initialized shall be initialized from an empty initializer list (8.5.4). [ Example:

struct S { int a; const char* b; int c; };
S ss = { 1, "asdf" };

initializes ss.a with 1, ss.b with "asdf", and ss.c with the value of an expression of the form int(), that is, 0. —end example ]

So as this is valid C++, although as noted using {} is not valid C99. One could argue that it is only a warning, but this seems like idiomatic C++ using {} for aggregate initialization and is problematic if we are using -Werror to turn warnings into errors.

Firstly, you can use the ({}) initializer with an std::array object, but semantically that stands for direct-initialization using copy-constructor from a temporary value-initialized std::array object, i.e. it is equivalent to

std::array<int, 10> arr(std::array<int, 10>{}); 

And it is actually supposed to compile.

Secondly, you don't really have to go the ({}) way when you can just do

std::array<int, 10> arr = {};

or

std::array<int, 10> arr{};

The first of the two is the most syntactically similar to your int arr[10] = {};, which makes me wonder why you didn't try it at first. Why did you decide to use ({}) instead of = {} when you built the std::array version of = {} syntax?

Enough people have pointed this out as a "problem" when compiling with -Werror that I think it's worth mentioning that the problem goes away if you just double up:

std::array<int, 10> arr{{}};

Does not produce any warning for me on gcc 4.9.2.

To add a bit as to why this solves it: my understanding was that std::array is actually a class with a C array as its only member. So double up on the braces makes sense: the outer braces indicate you are initializing the class, and then the inner braces default initialize the one and only member of the class.

Since there is no possible ambiguity when there is only one variable in a class, just using one pair of {} should be reasonable, but gcc is overly pedantic here, and warns.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!