为何从字符串字面量初始化带隐式string构造函数的类vector失败?
问题分析:vector列表初始化失败的原因
示例代码
#include <iostream> #include <map> #include <vector> using namespace std; class mc { string s; public: mc(const std::string s) : s{s}{}; // mc(const char * s) : s{s}{}; // 添加此行可让两种情况都正常运行 }; int main() { vector<mc> a = {"Hello", "there"}; //编译失败 vector<mc> b = {mc("Hello"), mc("there")}; //编译成功 }
编译器错误信息
第一种错误提示:
no matching function for call to mc::mc(const char&) note: candidate: ‘mc::mc(std::string)’ note: no known conversion for argument 1 from ‘const char’ to ‘std::string’
第二种错误提示:
/usr/include/c++/11/bits/stl_uninitialized.h:138:72: error: static assertion failed: result type must be constructible from value type of input range
问题原因
核心在于C++列表初始化的隐式转换限制,具体细节如下:
- 当用花括号初始化
vector<mc>时,编译器需要将列表中的const char*(字符串字面量退化成该类型)直接转换为mc对象,但这个过程需要两次连续的隐式转换:const char*→std::string(调用std::string的构造函数),再std::string→mc(调用mc的构造函数)。而C++标准明确禁止这种两次用户定义的隐式转换,因此编译失败。 - 换成
vector<string>时,const char*到std::string只需一次隐式转换,符合规则,所以可以正常编译。 - 而
vector<mc> b的写法是直接显式构造mc对象:mc("Hello")中,const char*隐式转换为std::string作为构造函数参数,这属于单次隐式转换(仅在函数参数传递时发生一次转换),符合C++的规则,因此可以成功编译。 - 添加
mc(const char * s)构造函数后,const char*可以直接一次转换为mc,满足列表初始化的要求,所以两种写法都能正常运行。
内容的提问来源于stack exchange,提问作者darmual
相关产品推荐
相关产品推荐

