C++ 为什么我可以将字符指定给字符串对象,但不能指定给字符串对象的向量?
C++Primer说,字符和字符串文字可以转换为C++ 为什么我可以将字符指定给字符串对象,但不能指定给字符串对象的向量?,c++,string,vector,character,variable-assignment,C++,String,Vector,Character,Variable Assignment,C++Primer说,字符和字符串文字可以转换为strings 我尝试将字符分配给字符串,如下所示: std::string s; s = 's'; 它没有给我任何错误 但是,当我尝试将字符分配给strings对象的vector时,如下所示: std::vector<std::string> svec; svec = {'a', 'b'}; std::vector svec; svec={'a','b'}; 它给了我一个错误。为什么?在第一个表达式中分配字符文字是有效的,因为s
string
s
我尝试将字符分配给字符串
,如下所示:
std::string s;
s = 's';
它没有给我任何错误
但是,当我尝试将字符分配给string
s对象的vector
时,如下所示:
std::vector<std::string> svec;
svec = {'a', 'b'};
std::vector svec;
svec={'a','b'};
它给了我一个错误。为什么?在第一个表达式中分配字符文字是有效的,因为
std::string
类接受char
第二个表达式中的字符文字参数不能隐式转换为字符串,就像字符串文字一样(即svec={“a”,“b”}
),因为std::string
:
表达方式:
svec = {"a", "b"};
svec = {'a', 'b'};
使用构造函数
string (const char* s);
表达方式:
svec = {"a", "b"};
svec = {'a', 'b'};
无法工作,因为不存在接受单个字符参数的构造函数
它所拥有的是一个构造函数,它接受一个初始值设定项列表
(如您在上一个链接中所看到的):
如您所知,这将在向量的前两个位置初始化两个字符串,一个包含“a”
,另一个包含“b”
对于向量第一个位置的单个字符串,可以使用:
svec = {{'a','b'}};
C++Primer说,字符和字符串文字可以转换为string
s
C样式的字符串文本可以隐式转换为std::string
,但char
s不能。这和作业不同
s='s'
之所以有效,是因为std::string
有一个重载字符char
ch
,如同通过assign(std::addressof(ch),1)
svec={'a','b'}
不起作用,因为std::vector
只重载了std::vector
或std::initializer\u list
,它们都不能从带括号的init list{a',b'}
中构造。您可能认为重载获取std::initializer\u list
可以用于这种情况,但是char
不能隐式地转换为std::string
(std::string
没有这样的获取char
),然后std::initializer\u list
无法从{a',b}构建
作为解决方法,您可以将代码更改为
svec = {"a", "b"};
“a”
的类型为const char[2]
并衰减const char*
,可以隐式地(通过使用const char*
)转换为std::string
,然后std::initializer\u list
从{a”,“b”}
构造并传递给std::vector::operator=/code>。当然svec={std::string(“a”),std::string(“b”)}
(或svec={“a”s,“b”s};
)也可以工作,std::initializer\u list
将直接构造,而无需对std::string
进行隐式转换,请考虑以下示例:
#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"};
}
要使用上面提到的std::vector
copy赋值运算符创建一个std::string
temporary,它位于外括号初始列表的一部分:
由于我们没有直接创建两个元素的std::initializer\u列表
,与上面的多个字符的std::initializer\u列表
形成单个字符串相比。也就是说,单个std::string
对象也是(零个或)多个char
元素的容器。理解这一点的关键是初始值设定项列表
首先,请注意,这不起作用:
std::string s('a');
但这确实:
std::string s{'a'};
原因是第一个需要一个接受单个char
的ctor,但是std::string
没有这样的构造函数。另一方面,第二种方法创建一个初始值设定项\u list
,其中std::string
有一个ctor
同样的道理也适用于
std::vector<std::string>> vs{ 'a', 'b' };
工作原理是,虽然std::string
缺少一个接受char
的构造函数,但它确实有一个接受char
的赋值运算符,因为std::vector
不能隐式地将char参数转换为字符串。
vector& operator=( std::initializer_list<T> ilist )
svec = {"a", "b"}; // svec.size() is now 2
std::string s('a');
std::string s{'a'};
std::vector<std::string>> vs{ 'a', 'b' };
std::vector<std::string>> vs{ {'a'}, {'b'} };
std::string s;
s = 'a';