cppxor2arr
cppxor2arr

Reputation: 305

Calling constructor with "()" is different from "{}"

Why are different results printed with these two lines of code?

std::cout << std::string{6, 's'}
std::cout << std::string(6, 's')

Upvotes: 4

Views: 249

Answers (4)

Barry
Barry

Reputation: 303487

Initialization with {}s is called list-initialization. List-initialization follows different rules than normal initialization in several ways, but the important case here has to do with std::initializer_list.

The rule is: if you're list-initializing a class type, T, and that class type has a constructor that takes a std::initializer_list<U>, and every element in the initializer list is convertible to U, then that constructor is selected. This happens before any other constructor is even considered, even if that constructor ends up being ill-formed (e.g. due to narrowing conversion). It's important to remember this rule - std::initializer_list always takes complete precedence in this case!


The two relevant constructors for std::string here are (just assuming std::string is a type and not a class template specialization for simpilcity):

string(std::initializer_list<char> init); // #1
string(size_t count, char ch );           // #2

When you write std::string{6, 's'}, that is list-initialization, so we look to see if there's a valid std::initializer_list constructor - and there is! Both int and char are convertible to char, so it's selected. In this case, there is no narrowing conversion because 6 fits in a char, so that's selected and used. The second constructor is never even considered. Note that std::string{300, '.'} is ill-formed, because we select the std::initializer_list<char> constructor but the conversion from 300 to char is narrowing. Even though the other constructor would work, it doesn't matter, we pick std::initializer_list<char> and error.

But when you write std::string(6, 's'), that isn't list-initialization. All constructors are considered here. The std::initializer_list constructor isn't a match - you can't initialize std::initializer_list<char> from an int - but the 2nd constructor is, so it's selected. This is more normal, familiar overload resolution at work.


A good rule of thumb is - {}-initialization is for initializing aggregates (which don't have constructors anyway) or initializing containers from a particular element set or to disambiguate the most vexing parse. If you're not doing any of those things, use ()s.

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409374

Because std::string have a constructor taking an std::initializer_list, the first example will use that constructor to create a string object with two characters. Initialization like this is called list initialization.

The second example will create a string object with six characters, all initialized to 's'. This form of initialization is called direct initialization.

List initialization and direct initialization can be the same, except that the possible conversions for larger types to smaller types are forbidden for list initialization, and as noticed here if the class have a constructor taking an std::initializer_list.

Upvotes: 9

Edgar Rokjān
Edgar Rokjān

Reputation: 17483

The reason is that different constructors are called.

std::string{6, 's'}

This code calls the constructor with initializer list:

basic_string( std::initializer_list<CharT> init, 
    const Allocator& alloc = Allocator() );

So 6 is converted to char and a string which consists of two chars is printed.

std::string(6, 's')

This code calls the next constructor:

basic_string( size_type count, 
    CharT ch, 
    const Allocator& alloc = Allocator() );

so a string which consists of 6 chars is printed.

Upvotes: 3

Michael232
Michael232

Reputation: 223

This happens because in the first case compilers prefers another overload and initializes string with symbols char(6) and 's'. You can check it by changing 6 to smth like 35 for printable char. While useful and solving most vexing parse problem, {} construction has it's caveats.

Upvotes: 3

Related Questions