2015-11-26 93 views
3

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>,其中列表初始化的细节表明将是第一个尝试构造函数的类型?

回答

4

[temp.deduct.call]/1模板参数推导由每个功能模板参数类型比较完成与所述呼叫的相应参数的类型(称为P)(称之为A)作为如下面所描述的。如果从P中删除引用和cv-限定符给出std::initializer_list<P'>对于某些P'并且参数是初始化符列表(8.5.4),则对初始化符列表的每个元素执行推导,取P'作为函数模板参数类型,然后初始化元素作为其参数。否则,初始化程序列表参数会导致该参数被视为未推导的上下文(14.8.2.5)。

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

+0

要澄清一下''initializer_list ''参数会导致'A(参数...)'中成功的模板参数推演。因此,我的CPP报价的第一行(转换为'initialiser_list'参数)适用于查找候选非模板构造函数,而您的报价适用于使用模板参数推导查找候选模板函数。如果模板或非模板函数都不提供合适的候选,则每个列表元素都被视为单独的参数。 – AntiElephant

+0

在** [dcl.init.list]/2 **中有一个注释:“将一个初始化程序列表作为参数传递给构造函数模板'template C(T)'的类'C'不会创建一个初始化程序-list构造函数,因为初始化程序列表参数会导致相应的参数成为非推导的上下文(14.8.2.1)。“这就是我导致** [temp.deduct.call] **的原因。现在,将程序中的'main'改为'std :: initializer_list l {2,3,4}; a a = 1;'编译。我不知道为什么。 –

+0

啊。 ** [temp.deduct.call]/1 **谈论参数是一个初始化列表(也就是用逗号分隔的一系列逗号分隔值),而不是'std :: initializer_list'的实例。区别很重要,两者不可互换。 –

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

相关问题