为什么初始值设定项列表与表达式列表的结果不同

Why does initializer-list have different result compared with expression-list

本文关键字:列表 表达式 结果 为什么      更新时间:2023-10-16

当我在下面写一些代码时,我觉得很奇怪。我期待着相同的输出,但事实证明这是错误的。为什么 2 个语句的输出不同,(表达式列表(和 {初始值设定项列表} 有什么区别?

cout << string(4, 'c') << endl;  
cout << string{ 4, 'c' } << endl; 

输出为:

cccc  
c   //a square '' before 'c'

从 cppreference.com:

否则,T的构造函数将分两个阶段进行考虑:

  • 将检查将std::initializer_list作为唯一参数或作为第一个参数(如果其余参数具有默认值(的所有构造函数,并通过针对类型std::initializer_list的单个参数的重载解析进行匹配

  • 如果前一阶段未生成匹配项,则T的所有构造函数都参与针对由大括号 init-list元素组成的参数集的重载解析,但限制是只允许非收缩转换。如果此阶段生成显式构造函数作为复制列表初始化的最佳匹配项,则编译将失败(注意,在简单的复制初始化中,根本不考虑显式构造函数(。

在您的情况下

string(4, 'c')

使用以下构造函数。

std::string(size_type count, 
char ch, 
const Allocator& alloc = Allocator() );

另一方面

string{ 4, 'c' }

使用以下构造函数。

std::string(std::initializer_list<char> ilist, 
const Allocator& alloc = Allocator() );

如果第二个构造函数没有在std::string中定义,这两个构造函数将产生相同的对象。

两者都是构造函数调用,但它们调用两个不同的构造函数。第一次调用(链接中的"2"(使用字符计数构造,因此在您的情况下你会得到 4 个'c。

第二个构造函数(链接中的"9"(采用std::initializer_list。当您使用大括号而不是参数进行构造时,如果类的构造函数采用initializer_list则它将始终优先。

如果有什么安慰的话,多年来,这种行为已经难倒了很多程序员......