Search code examples
c++constructorinitializer-list

Why does initializer-list have different result compared with expression-list


I feel weird when I write some code below. I am looking forward to the same output, but it turns out to be wrong. Why do the 2 statements have the different output, and what's the difference between (expression-list) and {initializer-list}?

cout << string(4, 'c') << endl;  
cout << string{ 4, 'c' } << endl; 

the output is:

cccc  
c   //a square '' before 'c'

Solution

  • From cppreference.com:

    Otherwise, the constructors of T are considered, in two phases:

    • All constructors that take std::initializer_list as the only argument, or as the first argument if the remaining arguments have default values, are examined, and matched by overload resolution against a single argument of type std::initializer_list

    • If the previous stage does not produce a match, all constructors of T participate in overload resolution against the set of arguments that consists of the elements of the braced-init-list, with the restriction that only non-narrowing conversions are allowed. If this stage produces an explicit constructor as the best match for a copy-list-initialization, compilation fails (note, in simple copy-initialization, explicit constructors are not considered at all).

    In your case

    string(4, 'c')
    

    uses the following constructor.

    std::string(size_type count, 
                char ch, 
                const Allocator& alloc = Allocator() );
    

    On the other hand,

    string{ 4, 'c' }
    

    uses the following constructor.

    std::string(std::initializer_list<char> ilist, 
                const Allocator& alloc = Allocator() );
    

    Had the second constructor not been defined in std::string, both of those would have produced identical objects.