C++ Primer says that character and string literals may be converted to strings.
I tried assigning a character to a string as:
std::string s;
s = 's';
And it gave me no error.
But, when I tried to assign characters to a vector of strings object as:
std::vector<std::string> svec;
svec = {'a', 'b'};
It gave me an error. Why?
C++ Primer says that character and string literals may be converted to
strings.
C-style string literals can convert to std::string implicitly, but chars can't.  That's different from assignment.
s = 's'; works because std::string has an overloaded operator= taking char.
- Replaces the contents with character
 chas if byassign(std::addressof(ch), 1)
svec = {'a', 'b'}; doesn't work because std::vector only has overloaded operator=s taking std::vector or std::initializer_list, both of them can't be constructed from braced-init-list {'a', 'b'}. You might think the overload taking std::initializer_list<std::string> could be used for this case, but char can't be converted to std::string implicitly (std::string doesn't have such converting constructor taking a char), then std::initializer_list<std::string> failed to be constructed from {'a', 'b'}.
As the workaround, you can change the code to
svec = {"a", "b"};
"a" is of type const char[2] and decays const char*, which could be converted to std::string implicitly (via the std::string's converting constructor taking const char*), then std::initializer_list<std::string> gets constructed from {"a", "b"} and passed to std::vector::operator=. Of course svec = {std::string("a"), std::string("b")}; (or svec = {"a"s, "b"s};) works too, std::initializer_list<std::string> will be constructed directly without such implicit conversion to std::string.
The assignment of a character literal in the first expression works because the std::string class has an overload for the assignment operator that takes char.
The character literal arguments in the second expression cannot be implicitly converted to strings, like string literals can (i.e. svec = {"a", "b"}), because std::string has a constructor for const char* but not for char:
The expression:
svec = {"a", "b"};
uses the constructor
string (const char* s);
The expression:
svec = {'a', 'b'};
can't work because no such constructor exists that takes a single character argument.
What it does have is a constructor that takes an initializer_list (as you can see in the previous link):
string (initializer_list<char> il); 
Available since C++11.
So to initialize std::string with character literals you need to use curly brackets (i.e. braced initializer list):
std::vector<std::string> svec;
svec = {{'a'}, {'b'}};
This will, as you know, initialize 2 strings in the first 2 positions of the vector one contains "a" and the other "b".
For a single string in the first position of the vector you can use:
svec = {{'a','b'}};
                        The key to understanding this is initializer lists.
First, note that this does not work:
  std::string s('a');
but this does:
  std::string s{'a'};
The reason is that the first one would require a ctor that takes a single char, but std::string does not have such a constructor. The second, on the other hand, creates an initializer_list<char>, for which std::string does have a ctor.
The exact same reasoning applies to
  std::vector<std::string>> vs{ 'a', 'b' };
versus
  std::vector<std::string>> vs{ {'a'}, {'b'} };
The first wants to use a non-existent std::string ctor taking a char, and the second uses initializer lists.
As for the original code, the reason that
  std::string s;
  s = 'a';
works is that while std::string lacks a ctor taking a char, it does have an assignment operator which takes a char.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With