下面的字符串代码调用了哪个构造函数?

Which constructor is getting called for below string code?

我在阅读 c++ primer 时遇到了 vector 的列表初始化示例,其中作者提到如果无法进行列表初始化,编译器会寻找其他方法来初始化对象。下面是字符串向量的例子。

vector<string> v8{10, "hi"};

这将创建一个包含 10 个值为“hi”的元素的向量。我认为这是因为列表初始化依赖于下面的构造函数来创建向量。

vector( size_type count, const T& value, const Allocator& alloc = Allocator());

我为 String

尝试了类似的列表初始化
std::string s1{10, 'c'};

我原以为它会创建一个字符串“cccccccccc”,因为它有一个可用的构造函数

basic_string( size_type count, CharT ch, const Allocator& alloc = Allocator() );

但它只打印“c”?这里使用了哪个字符串构造函数?

constructor 采取 std::initiazer_list 被调用。

constexpr basic_string( std::initializer_list<CharT> ilist,
                        const Allocator& alloc = Allocator() );

10 是一个 int,可以隐式转换为 char,而 std::initializer_list<char> 可以从 {10, 'c'} 构造为包含两个 [=14] =]s,第一个 ASCII 值为 10,第二个为 c.

另一方面,对于 std::vector<std::string>{10, "hi"} 不能用于构造 std::initializer_list<std::string>,因为 10 不能转换为 std::string ,则不会使用采用 std::initializer_list<std::string> 的构造函数。

这里发挥作用的是 direct-list-initialization 的规则,其中一种语法为

T object { arg1, arg2, ... };

这里,在std::string s{10, 'c'}的情况下,上面语法中的Tstd::string,适用的规则是

Otherwise, the constructors of T are considered, in two phases: All constructors that take std::initializer_list as the only argument, or as the first argument if the remaining arguments have default values, are examined, and matched by overload resolution against a single argument of type std::initializer_list

因为 std::string 的构造函数接受一个初始化列表,其他参数作为默认值,即 constructor (9)

basic_string( std::initializer_list<CharT> ilist,
              const Allocator& alloc = Allocator() );

参与此决议,因为 10 可以隐式转换为 char,您得到的是 2 个字符的 {'\n', 'c'}std::initializer_list<char>


std::vector<std::string> v{10. "hi"} 的情况下,Tdirect-list-initialization 的语法中是 std::vector<std::string> 如上所述。

现在,由于 10 不能隐式转换为 std::string,因此无法构造这样的 std::initializer_list<std::string>,因此 direct-list-initialization 的下一个替代方案是

If the previous stage does not produce a match, all constructors of T participate in overload resolution against the set of arguments that consists of the elements of the braced-init-list, with the restriction that only non-narrowing conversions are allowed.

这会产生与 constructor 3

的匹配
explicit vector( size_type count,
                 const T& value = T(),
                 const Allocator& alloc = Allocator());

因为这两个转换都不是非缩小的。


现在谈谈你想用 std::string s{10, 'c'} 实现的目标,应该使用 std::string s(10, c) 来完成,其中没有 list-initialization 涉及。

std::string s1{10, 'c'}, s2(10, 'c');
std::cout<<'['<<s1<<']'<<'['<<s2<<']'<<'\n';

输出:

[
c][cccccccccc]

请注意,打印 s1 会在 c 之前生成一个新行,因为它实际上是 ['\n', 'c'],而 s2 正是您所期望的,即 10 c个字符。