【问题标题】:List-initializer and variadic constructor列表初始化器和可变参数构造器
【发布时间】:2015-11-26 22:52:30
【问题描述】:

来自CPP reference 列表初始化:

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

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

  • 如果前一阶段没有产生匹配,则 T 的所有构造函数都参与重载决议,以针对由括号初始化列表的元素组成的参数集,限制只允许非缩小转换.如果此阶段生成显式构造函数作为复制列表初始化的最佳匹配,则编译失败(注意,在简单复制初始化中,根本不考虑显式构造函数)

所以首先考虑使用initializer_list 的构造函数。否则,列表的每个元素都被视为构造函数的参数。不过

#include <iostream>

using namespace std;

struct A{
    template <typename... Args> A(Args... li) { cout << sizeof...(Args) << endl;}
};

int main(){

    A a = {2,3,4};

}

输出为3,表示Args... 解包为int, int, int。为什么 Args... 不是简单地做成单数 initializer_list&lt;int&gt;,列表初始化的细节表明这是第一个尝试的构造函数类型?

【问题讨论】:

    标签: c++ templates c++11 initializer-list variadic


    【解决方案1】:

    [temp.deduct.call]/1 模板实参推导是通过比较每个函数模板形参类型(称为P)与调用对应实参的类型(调用它A) 如下所述。如果从 P 中删除引用和 cv-qualifiers 会为某些 P' 提供 std::initializer_list&lt;P'&gt; 并且参数是一个初始化列表 (8.5.4),然后对初始化列表的每个元素执行推导,取 P'作为函数模板参数类型,初始化元素作为其参数。否则,初始化列表参数会导致参数被视为非推导上下文 (14.8.2.5)。

    强调我的。因此,从 initializer_list&lt;int&gt; 类型的参数中推导构造函数的模板参数失败。

    【讨论】:

    • 为了清楚起见,initializer_list&lt;int&gt; 参数将导致A(Args...) 中的模板参数推导成功。因此,我的 CPP 引用的第一行(转换为 initialiser_list 参数)适用于查找候选非模板构造函数,而您的引用适用于使用模板参数推导查找候选模板函数。如果模板或非模板函数都没有提供合适的候选者,则每个列表元素都被视为一个单独的参数。
    • [dcl.init.list]/2中有一条注释:“将初始化列表作为参数传递给类C的构造函数模板template&lt;class T&gt; C(T)不会创建初始化列表构造函数,因为初始化列表参数会导致相应的参数成为非推导上下文 (14.8.2.1)。”这就是导致我[temp.deduct.call]的原因。现在,将程序中的main 更改为std::initializer_list&lt;int&gt; l{2,3,4}; A a = l; 确实可以编译。我不知道为什么。
    • 啊。 [temp.deduct.call]/1 讨论了参数是初始化列表(即用大括号括起来的逗号分隔值序列)而不是std::initializer_list 的实例的情况.区别很重要,两者不可互换。
    【解决方案2】:

    如果您显式提供带有std::initializer_list 的构造函数,则可以选择: Demo.

    template &lt;typename... Args&gt; A(Args...) 不是第一个参数std::initializer_list 的构造函数(即使第一个参数可能是std::initializer_list)。

    A a = {2, 3, 4} 中,{2, 3, 4} 没有类型。这不是std::initializer_list

    【讨论】:

      猜你喜欢
      • 2016-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-02
      • 1970-01-01
      • 2015-06-11
      • 1970-01-01
      • 2011-03-10
      相关资源
      最近更新 更多