空大括号是调用默认构造函数还是调用 std::initializer_list 的构造函数?

Posted

技术标签:

【中文标题】空大括号是调用默认构造函数还是调用 std::initializer_list 的构造函数?【英文标题】:Do empty braces call the default constructor or the constructor taking an std::initializer_list? 【发布时间】:2015-09-25 12:28:51 【问题描述】:

以下引自Effective Modern C++(第55页):

“假设你使用一组空大括号来构造一个支持默认构造函数并且还支持std::initializer_list构造的对象。你的空大括号是什么意思?等等。规则是你得到默认构造。”

我用 std::array: 试过这个

std::array<int, 10> arr;

并从 g++(版本 4.8.2)得到警告:

警告:缺少成员“std::array::_M_elems”的初始化程序

这是尝试从空的std::initializer_list 构造std::array 时得到的警告(有关此警告的讨论,请参见Why can I initialize a regular array from , but not a std::array)。

那么,为什么上面的代码行不被解释为调用默认构造函数呢?

【问题讨论】:

std::array 没有采用std::initializer_list 的构造函数,并且您在此处拥有的初始化程序也不是std::initailizer_list。它被称为支撑初始化列表。我不确定您为什么会收到警告,因为使用空大括号应该对嵌套数组进行值初始化。 @0x499602D2 查看我对链接问题的回答,gcc 具有攻击性,并且更高版本的 gcc 不会产生警告。 另请注意,他们在 DR 中以重要的方式更改了 C++11 标准。实际标准说明了一件事,但编译器应该做一些完全不同的事情。 @o11c 你指的是哪个DR?我不清楚您指的是哪种行为。 【参考方案1】:

这是因为std::array 是一个聚合,因此aggregate initialization 被执行,这在draft C++11 standard 部分8.5.4 [dcl.init.list] 中介绍: p>

类型 T 的对象或引用的列表初始化定义如下:

如果初始化列表没有元素并且 T 是具有默认构造函数的类类型,则对象为 值初始化。

否则,如果 T 是聚合,则执行聚合初始化 (8.5.1)。

double ad[] =  1, 2.0 ; // OK
int ai[] =  1, 2.0 ; // error: narrowing

struct S2 
  int m1;
  double m2, m3;
;

S2 s21 =  1, 2, 3.0 ; // OK
S2 s22  1.0, 2, 3 ; // error: narrowing
S2 s23  ; // OK: default to 0,0,0

我们可以看看它是否不是一个聚合然后列表继续说:

否则,如果 T 是 std::initializer_list 的特化,则 initializer_list 对象为 如下所述构造并用于根据初始化规则初始化对象 来自同一类型的类的对象 (8.5)。 否则,如果 T 是类类型,则考虑构造函数。枚举适用的构造函数 并且通过重载决议(13.3、13.3.1.7)选择最好的一个。如果缩小转换(见 下面) 需要转换任何参数,程序格式错误。

我们可以确认std::array 是来自23.3.2.1 部分的聚合[array.overview]

数组是一个聚合(8.5.1),可以用 语法

array<T, N> a =  initializer-list ;

其中 initializer-list 是一个逗号分隔的列表,最多包含 N 个元素 其类型可转换为 T。

引用的8.5.1 部分是8.5.1 聚合[dcl.init.aggr] 并说:

当一个聚合被初始化列表初始化时,指定 在 8.5.4 中,初始化列表的元素被视为 聚合成员的初始化器,增加下标 或会员订单[...]

然后我们回到8.5.4 部分,这是我们开始的地方。

【讨论】:

能否提供您引用的标准文档的链接(当然,如果它可以免费访问)? @MeirGoldenberg 在答案中添加了链接,您可以看到Where do I find the current C or C++ standard documents? 列出了所有可供公众使用的草稿。

以上是关于空大括号是调用默认构造函数还是调用 std::initializer_list 的构造函数?的主要内容,如果未能解决你的问题,请参考以下文章

new一个对象后面加括号与不加括号的区别

为啥 std::in_place_t 的构造函数默认且显式?

C++:调用无参数的构造函数为啥不加括号

js构造函数中this介绍

js构造函数中this介绍

成员函数