问题
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