This is a construct of string:
string s {"Hello world!"};
And string class has the following constructor that I think might be bound to:
From char pointer/array:
string (const char* s);
From initializer_list:
string (initializer_list<char> il);
At first I thought it will be calling initializer_list
because the parameters are braced. Then I saw the initializer_list takes an argument of char
but that was a string.
Then I realize the {""}
can be implicitly converted to char[]
thus it might call the first constructor... In this case, is a pair of parentheses automatically added around the list(e.g. like ({""})
)?
So which constructor does it actually call?
How about this:
double d1 (100);
double d2 {100};
Are they the same?
Assume string also has a constructor like string(initializer_list<string>)
, then which one will it call?
In C++11, curly braces {}
are used for uniform initialization. Any object that can be initialized can be initialized with curly braces. Preference is given to constructors that take initializer_list<T>
, so if a curly-brace initialization could match more than one constructor and one of them takes an initializer_list
, that will be selected. However, if no initializer_list
constructors match, the other constructors are also considered.
For example:
vector<int> two_elems{5,10}; // A vector containing two elements
vector<int> five_elems(5,10); // A vector containing five elements
vector<int> five_elems_also{10,10,10,10,10}; // Equivalent to the above
In your example, you're initializing a string
with a char const[13]
. This would match initializer_list<char const*>
, if string
had such a constructor, but it doesn't match initializer_list<char>
. So the parameter is instead matched against the other constructors, and the constructor taking char const*
is the best match.
Note that because of the ambiguity, it's probably best not to initialize containers (such as vector
, set
, list
, or even string
) using brace initialization unless you intend to use the initializer_list
constructors. For example, there's no way to call vector<size_t>
's constructor that takes size_t, T
using brace-initialization, since that argument list will also match the initializer_list
constructor. As another example:
vector<char const*> vec_of_strs{ 5, 0 }; // Creates a vector holding *5* nullptrs
vector<unsigned> vec_of_nums{ 5, 0 }; // Creates a vector holding *2* numbers
It's not immediately obvious that the two lines above are calling very different constructors, and if the type of one were changed to the other during maintenance (or the code occurred in a template), programmers may be very surprised at the sudden behavior change.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With