C++ 为什么我可以将字符指定给字符串对象,但不能指定给字符串对象的向量?

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

C++Primer说,字符和字符串文字可以转换为
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';