列表初始值设定项和可变构造函数

List-initializer and variadic constructor

本文关键字:构造函数 列表      更新时间:2023-10-16

从CPP参考列表初始化:

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

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

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

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

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

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

如果显式提供具有std::initializer_list的构造函数,则会选择:演示。

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

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