列表初始化器和可变参数构造函数

List-initializer and variadic constructor

来自 CPP reference 列表初始化:

Otherwise, the constructors of T are considered, in two phases:

  • All constructors that take std::initializer_list as the only argument, or as the first argument if the remaining arguments have default values, are examined, and matched by overload resolution against a single argument of type std::initializer_list

  • If the previous stage does not produce a match, all constructors of T participate in overload resolution against the set of arguments that consists of the elements of the braced-init-list, with the restriction that only non-narrowing conversions are allowed. If this stage produces an explicit constructor as the best match for a copy-list-initialization, compilation fails (note, in simple copy-initialization, explicit constructors are not considered at all)

所以首先考虑使用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.deduct.call]/1 Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below. If removing references and cv-qualifiers from P gives std::initializer_list<P'> for some P' and the argument is an initializer list (8.5.4), then deduction is performed instead for each element of the initializer list, taking P' as a function template parameter type and the initializer element as its argument. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context (14.8.2.5).

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

如果您使用 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.