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

时间:2014-11-17 01:35:11

标签: c++ c++11 copy-constructor list-initialization copy-initialization

在C ++ 11之前,我们可以通过编写类似于A a = 1;的{​​{1}}来复制初始化。A a = A(1);或多或少等同于A a = {1, 2};。也就是说,首先创建临时,然后调用复制ctor。无论版本是否复制,都必须在概念上如此,并且必须可以访问复制文件。

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

所以,我的问题是:概念上像{{1}}这样的表达式的确切语义是什么?通过概念,复制省略不会妨碍。

1 个答案:

答案 0 :(得分:9)

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

  

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

     
      
  • [...]
  •   
  • 否则,如果T是类类型,则考虑构造函数。该   列举了适用的构造函数,并选择最佳构造函数   通过重载决议(13.3,13.3.1.7)。如果缩小   转换(见下文)是转换任何参数所必需的,   该计划格式不正确。
  •   

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

  

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

     
      
  • 最初,候选函数是类T的初始化列表构造函数(8.5.4),参数列表包含   初始化列表作为单个参数。

  •   
  • 如果找不到可行的初始化列表构造函数,则再次执行重载解析,其中候选函数全部   类T的构造函数和参数列表由   初始化列表的元素。

  •   
     

如果初始化列表没有   elements和T有一个默认构造函数,第一阶段被省略   在复制列表初始化中,如果选择了explicit构造函数,则   初始化是不正确的。

因此,如果没有找到初始化列表构造函数(如您所示),则初始化列表的元素构成构造函数调用的参数。实际上,直接列表初始化和复制列表初始化的差异由最后一个粗体句子覆盖。

这是列表初始化的优点之一:它不需要存在不会被使用的特殊成员函数。