列表初始化器和可变参数构造函数
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
.
来自 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 itA
) as described below. If removing references and cv-qualifiers fromP
givesstd::initializer_list<P'>
for someP'
and the argument is an initializer list (8.5.4), then deduction is performed instead for each element of the initializer list, takingP'
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
.