Consider the following example:
#include <initializer_list>
#include <vector>
#include <string>
#include <type_traits>
int main() {
std::vector<std::string> svec;
// Non-ambigously deduced to std::initializer_list<char>.
auto a = {'a', 'b'};
static_assert(std::is_same_v<std::initializer_list<char>, decltype(a)>);
// (A)
// error: no match for 'operator=' (... std::vector<std::string> and 'std::initializer_list<char>')
//svec = a;
//svec = std::initializer_list<char>{'a', 'b'};
// error:
// error: unable to deduce 'std::initializer_list<auto>' from '{{'a', 'b'}}'
//auto b = {{'a', 'b'}};
// (B)
// OK.
// After all the following copy assingnments, svec.size() is 1 (a single "ab" element).
svec = {{'a', 'b'}};
svec = std::initializer_list<std::string>{{'a', 'b'}};
svec = std::initializer_list<std::string>{std::initializer_list<char>{'a', 'b'}};
svec = std::initializer_list<std::string>{"ab"};
}
The error message at (A) is self-explanatory: there exist no copy assignment operator for std::vector<std::string> to assign a std::initializer_list<char> argument to it. The only near-viable overload of std::vector<T,Allocator>::operator= requires an argument of type std::initializer_list<T>:
vector& operator=( std::initializer_list<T> ilist );
Replaces the contents with those identified by initializer list ilist.
but T in this example is std::string, thus this overload is not viable.
In (B), on the other hand, we use the nested braced init syntax {{'a', 'b'}} such that the inner braced init list represents a std::initializer_list<char>, which may make use of the following std::string constructor:
basic_string( std::initializer_list<CharT> ilist,
const Allocator& alloc = Allocator() );
to create a single std::string temporary which is in turned part of the outer braced init list, making use of std::vector copy assignment operator mention above:
vector& operator=( std::initializer_list<T> ilist )
The result of the different variations of (B) is the same: copy assigning to the svec vector a vector of a single std::string element.
Finally, note that if you were to copy assign to svec using a braced init list of "-separated strings, the result is copy assigning a vector of two elements:
svec = {"a", "b"}; // svec.size() is now 2
as we are no directly creating a std::initializer_list<std::string> of two elements, as compared to above where a std::initializer_list<char> of several characters result in a single string. I.e., a single std::string object is also a container of (zero or) several char elements.