Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this code to initialize a string to a single character call the initializer_list constructor?

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?

like image 359
templatetypedef Avatar asked Aug 28 '17 21:08

templatetypedef


People also ask

What does a string initialize to in C++?

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.

Why do we use initializer list in C++?

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.

What is std :: Initializer_list?

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 .


1 Answers

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.

like image 136
Nicol Bolas Avatar answered Sep 30 '22 05:09

Nicol Bolas