string s5("hiya");// direct initialization
string s6 = ("hiya");// copy initialization
string s7 = "hiya";// copy initialization
string s8(10, 'c'); // direct initialization; s8 is cccccccccc
string s9 = string(10, 'c'); // copy initialization
//
string s4(10, 'c');// s4 is cccccccccc
When we have a single initializer, we can use either the direct or copy form of initialization. When we initialize a variable from more than one value, such as in the initialization of s4 above, we must use the direct form of initialization:
Several values refers to the number of constructor arguments.
Consider...
string s4(10, 'c'); //s4 is "cccccccccc"There are two (i.e. several) values - 10 and 'c'.
In that situation you can't get the same behaviour from e.g....
string s4 = 10, 'c'; // doesn't work as above...because the value to assign is evaluated as an expression with a comma operator: the left hand 10 is discarded, then the expression evaluates as simply 'c', which becomes the only argument to the string constructor. There is no matching constructor taking a single char argument, nor anything the char can undergo Standard Conversion to, so you'll get a compilation error. (The closest constructor is...
basic_string( size_type count, CharT ch, const Allocator& alloc = Allocator() );...for whatever that's worth....)
With C++11 you can use braces to create a single std::initializer_list argument with which you can call the constructor...
basic_string( std::initializer_list<CharT> init, const Allocator& alloc = Allocator() );...but you could argue that's not calling a constructor with multiple values, but a single value containing sub-values....