从列表初始化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>
,列表初始化的细节表明这是第一个尝试类型的构造函数?
答案 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
。