I was recently working on a C++ project and came across an edge case with the string constructors that I can't fully understand. The relevant code (which you can run here) is as follows:
#include <iostream>
#include <string>
using namespace std;
int main() {
string directParens(1, '*');
string directBraces{1, '*'};
string indirectBraces = {1, '*'};
cout << directParens.size() << endl; // 1
cout << directBraces.size() << endl; // 2
cout << indirectBraces.size() << endl; // 2
return 0;
}
The brace-initialized versions of the strings end up having two characters in them, namely, a char
with numeric value 1 followed by a star.
I don't understand why the brace-initialized versions of the string invoke the initializer_list
constructor rather than the constructor taking in a size and a character. The initializer_list
constructor has this signature:
basic_string(std::initializer_list<CharT> init,
const Allocator& alloc = Allocator());
Given that string
is an alias for basic_string
char, the specific signature would be
string(std::initializer_list<char> init,
const Allocator& alloc = Allocator());
How is the initializer {1, '*'}
, which contains elements both of type int
and of type char
, matching this constructor? I was under the impression that all literals in an std::initializer_list
must have the same type - is that incorrect?
This string object is initialized to hold no characters and can properly report its zero length and absence of data elements using class member functions.
Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.
An object of type std::initializer_list<T> is a lightweight proxy object that provides access to an array of objects of type const T .
How is the initializer {1, '*'}, which contains elements both of type int and of type char, matching this constructor?
Because both the literal 1
and the character '*'
are convertible to char
without using a narrowing conversion. Therefore, they are eligible to call the initializer_list<char>
constructor. And initializer_list
constructors always have priority when using list initialization. If it is possible to call the initializer_list
constructor from the parameters, then it will.
Never use braced-init-lists with containers unless you intend the elements in the list to be elements of the container. If you intend them to be constructor parameters, then use a constructor.
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