C++ 列表初始值设定项和变量构造函数
从列表中初始化: 否则,将分两个阶段考虑T的施工人员:C++ 列表初始值设定项和变量构造函数,c++,templates,c++11,initializer-list,variadic,C++,Templates,C++11,Initializer List,Variadic,从列表中初始化: 否则,将分两个阶段考虑T的施工人员: 所有将std::initializer_list作为唯一参数或将其作为第一个参数(如果其余参数具有默认值)的构造函数都将被检查,并通过重载解析与std::initializer_list类型的单个参数进行匹配 如果前一个阶段没有生成匹配项,则T的所有构造函数都会参与针对由大括号init列表元素组成的参数集的重载解析,限制条件是只允许非收缩转换。如果此阶段生成显式构造函数作为副本列表初始化的最佳匹配,编译将失败(注意,在简单副本初始化中,
- 所有将std::initializer_list作为唯一参数或将其作为第一个参数(如果其余参数具有默认值)的构造函数都将被检查,并通过重载解析与std::initializer_list类型的单个参数进行匹配
- 如果前一个阶段没有生成匹配项,则T的所有构造函数都会参与针对由大括号init列表元素组成的参数集的重载解析,限制条件是只允许非收缩转换。如果此阶段生成显式构造函数作为副本列表初始化的最佳匹配,编译将失败(注意,在简单副本初始化中,根本不考虑显式构造函数)
初始值设定项\u 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};
}
#包括
使用名称空间std;
结构A{
模板A(Args…li){cout
[temp.decrete.call]/1通过比较每个函数模板参数类型(调用它p
)与调用的相应参数类型(调用它A
)来完成模板参数推断如下所述。如果从P
中删除引用和cv限定符会给出std::initializer\u列表,如果您明确提供了一个带有
std::initializer\u列表的构造函数,则将选择:
模板A(Args…
不是具有第一个参数的构造函数std::initializer\u list
(即使第一个参数可能是std::initializer\u list
)
在A={2,3,4}
中,{2,3,4}
没有类型。它不是一个std::initializer\u列表
只是要清楚,一个initializer\u列表
参数将导致A(Args…
)中成功的模板参数推断。因此,我的CPP引号的第一行(转换为初始化器列表
参数)适用于查找候选非模板构造函数,而您的报价适用于使用模板参数推断查找候选模板函数。如果模板函数或非模板函数均未提供合适的候选函数,则每个列表元素都被视为单独的参数。[dcl.init.list]/2中有一条注释:“将初始值设定项列表作为参数传递给类C
的构造函数模板template C(T)
,并不会创建初始值设定项列表构造函数,因为初始值设定项列表参数会导致相应的参数为非推断上下文(14.8.2.1)。”这就是导致我选择[temp.Decrete.call]的原因。现在,将程序中的main
更改为std::initializer\u list l{2,3,4};A=l;
确实可以编译。我不确定为什么。啊。[temp.decreate.call]/1讨论了参数是初始值设定项列表的情况(即,用大括号括起来的逗号分隔的值序列),而不是std::initializer\u list的实例。区别很重要,两者不能互换。