Advertisement Jump to content
Sign in to follow this  

Why does this work?

This topic is 4583 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have this code here, and to my surprise it worked!
#include <string>
#include <iostream>

template<typename T>
struct Damage
    T d[12];

Damage<std::string> damageNames  = {"None", "", "Blunt", "Sharp", "Magic", "Fire", "Water", "Earth", "Air", "Cold", "Electric", "Poison"};

int main()

It outputs "Fire" for me. I'd like to know: -Why does it work? -Is it supposed to work according to the C++ standard? -Is it safe? -Is the {"None", "", "Blunt", "Sharp", "Magic", "Fire", "Water", "Earth", "Air", "Cold", "Electric", "Poison"} called an initializer list? Thanks!

Share this post

Link to post
Share on other sites
Your struct is considered an aggregate, as it has no user declared constructors, no private or protected non static member variables, no virtual functions and no base classes. Aggregates can be initialized with an aggregate initializer list, which is the brace enclosed list. Each item in the list is applied as an argument for a constructor for the corresponding element in the aggregate. In the case of an array member variable of an aggregate each successive element in the aggregate intializer list is applied to successive array elements.

Share this post

Link to post
Share on other sites
Guest Anonymous Poster
thats a fully valid way to assign values to an array.

and ofcourse it works with any type aslong as that type is specified when the struct is created, 'Damage' creates a damage struct where 'd' is an array of strings.

Share this post

Link to post
Share on other sites
It should be noted that in this case, there are two nested aggregates -- the struct Damage, and its member array d. In general, each sub-aggregate in the aggregate initializer should be delimited by its own curly braces, for clarity's sake. The Standard, however, allows omitting everything but the outermost pair if there are no ambiguities. This is why the above code compiles. Some examples:

struct foo { int i; int a[2]; int j; };

foo f1 = { 1, { 2, 3 }, 4 }; // i==1, a[0]==2, a[1]==3, j==4
foo f2 = { 1, 2, 3, 4 }; // same as f1
foo f3 = { 1, 2 }; // i==1, a[0]==2, a[1]==0, j==0 (zero-initialization guaranteed!)
foo f4 = { 1, { 2 } }; // same as f3
foo f5 = { 1, 2, 3 }; // i==1, a[0]==2, a[1]==3, j==0
foo f6 = { 1, { 2 }, 4 }; // i==1, a[0]==2, a[1]==0, j==4
foo f7 = { 1, { }, 4 }; // i==1, a[0]==0, a[1]==0, j==4
foo f8 = { }; // i==0, a[0]==0, a[1]==0, j==0
foo f9; // contents random -- NOT zero-initialized! However, any and all
// member *objects* (as opposed to members of built-in types)
// WOULD be initialized by calling the default constructor.

It is interesting to note that the following is a valid syntax for initializing a variable of a built-in type:

int i = { 42 };

However, surprisingly (in light of the above) the following *isn't* well-formed:

struct s { int i; }
s s1 = { { 42 } };

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using, you agree to our community Guidelines, Terms of Use, and Privacy Policy. is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!