为什么我可以将字符分配给字符串对象而不是字符串对象的向量?

Mas*_*son 23 c++ string vector character variable-assignment

C++ Primer 说字符和字符串文字可以转换为strings。

我尝试为 a 分配一个字符string

std::string s;
s = 's';
Run Code Online (Sandbox Code Playgroud)

它没有给我任何错误。

但是,当我尝试将字符分配给 a vectorof strings 对象时:

std::vector<std::string> svec;
svec = {'a', 'b'};
Run Code Online (Sandbox Code Playgroud)

它给了我一个错误。为什么?

son*_*yao 27

C++ Primer 说字符和字符串文字可以转换为strings。

C 样式字符串文字可以std::string隐式转换为,但chars 不能。这与任务不同。

s = 's';有效,因为std::string有一个超载的operator=take char

  1. 用字符替换内容,ch就像assign(std::addressof(ch), 1)

svec = {'a', 'b'};不起作用,因为std::vector只有重载的operator=s接受std::vectoror std::initializer_list,它们都不能从 braced-init-list 构造{'a', 'b'}。您可能认为在std::initializer_list<std::string>这种情况下可以使用重载,但char不能std::string隐式转换为(std::string没有这样的转换构造函数取 a char),然后std::initializer_list<std::string>无法从{'a', 'b'}.

作为解决方法,您可以将代码更改为

svec = {"a", "b"};
Run Code Online (Sandbox Code Playgroud)

"a"是 类型const char[2]和衰变const char*,可以std::string隐式转换为(通过std::string的转换构造函数采取const char*),然后std::initializer_list<std::string>从 构造{"a", "b"}并传递给std::vector::operator=。当然svec = {std::string("a"), std::string("b")};(or svec = {"a"s, "b"s};) 也std::initializer_list<std::string>可以工作,将直接构造而无需隐式转换为std::string.


ana*_*ciu 16

第一个表达式中字符文字的赋值有效,因为std::string该类具有赋值运算符的重载,该运算符采用char.

第二个表达式中的字符文字参数不能隐式转换为字符串,就像字符串文字可以(即svec = {"a", "b"}),因为std::string 有一个构造函数 forconst char*但不是 forchar

表达方式:

svec = {"a", "b"};
Run Code Online (Sandbox Code Playgroud)

使用构造函数

string (const char* s);
Run Code Online (Sandbox Code Playgroud)

表达方式:

svec = {'a', 'b'};
Run Code Online (Sandbox Code Playgroud)

无法工作,因为不存在接受单个字符参数的构造函数。

它所拥有的是一个构造函数,它采用一个initializer_list(如您在上一个链接中所见):

string (initializer_list<char> il); 
Run Code Online (Sandbox Code Playgroud)

自 C++11 起可用

因此,要std::string使用字符文字进行初始化,您需要使用大括号(即大括号初始化列表):

std::vector<std::string> svec;
svec = {{'a'}, {'b'}};
Run Code Online (Sandbox Code Playgroud)

如您所知,这将在向量的前 2 个位置初始化 2 个字符串,一个包含"a",另一个"b"

对于向量第一个位置的单个字符串,您可以使用:

svec = {{'a','b'}};
Run Code Online (Sandbox Code Playgroud)


小智 7

理解这一点的关键是初始化列表。

首先,请注意这不起作用:

  std::string s('a');
Run Code Online (Sandbox Code Playgroud)

但这确实:

  std::string s{'a'};
Run Code Online (Sandbox Code Playgroud)

原因是第一个需要一个带有单个 的ctor char,但std::string没有这样的构造函数。另一方面,第二个创建了一个initializer_list<char>,它std::string确实有一个ctor。

完全相同的推理适用于

  std::vector<std::string>> vs{ 'a', 'b' };
Run Code Online (Sandbox Code Playgroud)

相对

  std::vector<std::string>> vs{ {'a'}, {'b'} };
Run Code Online (Sandbox Code Playgroud)

第一个想要使用一个不存在的std::stringctor 取 a char,第二个使用初始化列表。

至于原始代码,原因是

  std::string s;
  s = 'a';
Run Code Online (Sandbox Code Playgroud)

有效的是,虽然std::string缺少一个带 a 的ctor char,但它确实有一个带 a 的赋值运算符char