复制列表初始化是否在概念上调用复制ctor?

Lin*_*gxi 9 c++ copy-constructor copy-initialization c++11 list-initialization

在C++ 11之前,我们可以通过编写类似于A a = 1;或多或少相当的东西来进行复制初始化A a = A(1);.也就是说,首先创建临时,然后调用复制ctor.无论版本是否复制,这必须是概念上的,并且必须可以访问复制文件.

使用C++ 11中的列表初始化,我们可以通过写入来进行复制列表初始化A a = {1, 2};.在我看来,这应该或多或少相当于A a = A(1, 2);.但是,在GCC和clang上,A a = {1, 2}即使复制和移动ctor不可访问(通过声明为私有)也会编译.但是,A a = 1;如果相应的复制/移动ctor不可访问,则不会在GCC或clang上编译.所以,A a = {1, 2};似乎或多或少等同于A a{1, 2};直接列表初始化.这与实际直接列表初始化之间的区别在于,A a = {1, 2};如果采用两个整数的ctor是显式的,则不会编译.在这方面,A a = {1, 2};类似于复制初始化.

所以,我的问题是:A a = {1, 2};概念上表达式的确切语义是什么?从概念上讲,复制省略不会妨碍.

Col*_*mbo 9

标准很好地描述了它; [dcl.init.list]/3:

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

  • [...]
  • 否则,如果T是类类型,则考虑构造函数.枚举适用的构造函数,并通过重载决策(13.3,13.3.1.7)选择最佳构造函数.如果转换任何参数需要缩小转换(见下文),则程序格式错误.

[over.match.list](强调我的):

当非聚合类类型的对象T被列表初始化(8.5.4)时,重载决策分两个阶段选择构造函数:

  • 最初,候选函数是类的初始化列表构造函数(8.5.4),T参数列表由初始化列表作为单个参数组成.

  • 如果找不到可行的初始化列表构造函数,则再次执行重载解析,其中候选函数是类的所有构造函数,T参数列表由初始化列表的元素组成.

如果初始化列表没有元素且T具有默认构造函数,则省略第一个阶段.
在copy-list-initialization中,如果explicit选择了构造函数,则初始化是错误的.

因此,如果没有找到初始化列表构造函数(如您所示),则初始化列表的元素构成构造函数调用的参数.
实际上,直接列表初始化和复制列表初始化的唯一区别在于最后一个粗体句子.

这是列表初始化的优点之一:它不需要存在无论如何都不会使用的特殊成员函数.

  • @Lingxi [**真的吗?**](http://coliru.stacked-crooked.com/a/d85bfae98f38bea3) (3认同)