List-initializer和variadic构造函数

时间:2015-11-26 22:52:30

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

从列表初始化CPP reference开始:

  

否则,T的构造函数分为两个阶段:

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

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

  •   

因此首先考虑使用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<int>,列表初始化的细节表明这是第一个尝试类型的构造函数?

2 个答案:

答案 0 :(得分:4)

  

[temp.deduct.call] / 1 模板参数推断是通过将每个函数模板参数类型(称为P)与调用的相应参数的类型进行比较来完成的(如下所述,称之为A)。如果从P中删除引用和cv限定符,为std::initializer_list<P'>提供P',并且参数是初始化列表(8.5.4),则会对初始化程序的每个元素执行推导list,将P'作为函数模板参数类型,将initializer元素作为其参数。否则,初始化列表参数会导致该参数被视为非推导上下文(14.8.2.5)。

强调我的。因此,类型为initializer_list<int>的参数的构造函数的模板参数推断失败。

答案 1 :(得分:1)

如果明确提供了std::initializer_list的构造函数,则会选择: Demo

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

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