下面的字符串代码调用了哪个构造函数?
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'}
的情况下,上面语法中的T
是std::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"}
的情况下,T
在 direct-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
个字符。
我在阅读 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'}
的情况下,上面语法中的T
是std::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"}
的情况下,T
在 direct-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
个字符。