C++11 direct-list-initialization syntax

有些话、适合烂在心里 提交于 2019-12-12 03:45:34

问题


After reading up on list-initialization and its various flavours, I decided to test out some features in an openGL ES app I'm writing using Xcode and Objective-C++, until I ran into something rather obscure.

I've known about (and frequently implement) the conventional C style structure initialization using the following syntax to initialize POD, such as a GLKVector2, for example:

GLKVector2 point = { 0,0 };    //copy-initialized

but this approach may not always be what's intended by the programmer. So, by removing the assignment (and a needless copy construction operation), in favour of direct-initilization, one would assume (from the documentation) the above declaration would appear like so:

GLKVector2 point{ 0,0 };    //direct-initialized, but generates compile error

However, the compiler doesn't complain when the code looks like this:

GLKVector2 point{ { 0,0 } };

To me, this appears as point is being direct-initialized from a temporary created from the inner structure { 0,0 } and thus not offering any advantage over the first approach; the temporaries still have to be allocated and deallocated.

Or perhaps this issue is simply the nature of the union/struct layout used by GLKit types confusing the compiler.

Some clarification on this odd syntax, before further implementation in the code, would be much appreciated


回答1:


The outer braces delimit the initializer for the object itself, the inner braces are the initializer for a member inside the object, e.g.

GLKVector2 v = { initializers-for-members };

where initializers-for-members is { 0, 0 } because the type has an array member, of two elements, and you initialize an array of two members with { a, b }.

C++ supports "brace elision" (8.5.1 [dcl.init.aggr] paragraph 11) which means nested braces can be left out of the initializer under certain circumstances, but in C++11 brace elision is only allowed for copy-initialization. This is why you don't need two sets of braces for the copy-init case, but do need them for direct-init.

Since C++11 was completed the rules have been changed by DR 1270 to allow brace elision in the direct-list-initialization case too, but that's a change made to the post-C++11 draft and not widely supported yet.




回答2:


According to docs GLKVector2 is:

union _GLKVector2
   {
   struct { float x, y; };
   struct { float s, t; };
      float v[2];
};
typedef union _GLKVector2 GLKVector2;

That's why you need double braces, you're initializing by initializing a union member. Member-wise aggregate initialization occurs in-place. If it were a flat structure, your single-braces assumption would work. This also happens when initializing an std::array (e.g. std::array<int, 2> a{{1, 2}}) because it's a POD aggregate, and no temporary C arrays are involved.

You should look at aggregate initialization.

EDIT

Actually, looking up the docs, there're rules about brace elision (only allowed in copy-initialization context) that may be of interest.



来源:https://stackoverflow.com/questions/15122109/c11-direct-list-initialization-syntax

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