在明确构造一个 std::initializer_list<U>
时,可以使用类模板参数推导(例如使用 CTAD)推断模板参数(U
)吗?
换句话说,我知道以下语句是有效的:
std::initializer_list<int> x1{1, 2, 3};
std::initializer_list<int> x2 = {1, 2, 3};
auto x3 = std::initializer_list<int>{1, 2, 3};
但以下陈述是否也有效?
std::initializer_list x1{1, 2, 3};
std::initializer_list x2 = {1, 2, 3};
auto x3 = std::initializer_list{1, 2, 3};
编译器对于 std::initializer_list
的模板参数能否被推导存在分歧:
#include <initializer_list>
struct s {
s(std::initializer_list<int>);
};
void f() {
std::initializer_list x1{1, 2, 3}; // Clang ERROR; GCC OK; MSVC OK
std::initializer_list x2 = {1, 2, 3}; // Clang ERROR; GCC OK; MSVC OK
auto x3 = std::initializer_list{1, 2, 3}; // Clang ERROR; GCC OK; MSVC OK
s x4(std::initializer_list{1, 2, 3}); // Clang ERROR; GCC ERROR; MSVC OK
s x5{std::initializer_list{1, 2, 3}}; // Clang ERROR; GCC OK; MSVC OK
s x6 = s(std::initializer_list{1, 2, 3}); // Clang ERROR; GCC OK; MSVC OK
s x7 = s{std::initializer_list{1, 2, 3}}; // Clang ERROR; GCC OK; MSVC OK
s x8 = std::initializer_list{1, 2, 3}; // Clang ERROR; GCC OK; MSVC OK
void g(std::initializer_list<int>);
g(std::initializer_list{1, 2, 3}); // Clang ERROR; GCC OK; MSVC OK
}
(在Compiler Explorer上查看此示例。)
已测试的编译器:
- 使用
-std=c++17 -stdlib=libc++
和-std=c++17 -stdlib=libstdc++
的Clang版本7.0.0 - 使用
-std=c++17
的GCC版本8.3 - 使用
/std:c++17
的MSVC版本19.16
template<class T> auto X(std::initializer_list<T>) -> std::initializer_list<T>;
然后[over.match.class.deduct]指示使用提供的初始化器{1,2,3}
,将函数模板视为初始化某些虚构类类型的构造函数模板,然后进入[over.match.list]。如果这样做,您将推断出T=int
。 - T.C.namespace std { template<class T> initializer_list(std::initializer_list<T>) -> initializer_list<T>; }
- strager