在显式构造std::initializer_list<U>时,是否可以推导模板参数(例如,使用类模板参数演绎(CTAD) )?
换言之,我知道以下声明是有效的:
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
}(请参阅编译器资源管理器上的示例。)
经测试的编者:
-std=c++17 -stdlib=libc++和-std=c++17 -stdlib=libstdc++的Clang版本7.0.0-std=c++17/std:c++17的MSVC版本19.16发布于 2020-08-15 14:08:27
这是一个Clang错误,在Nicol Bolas的“永不改变的答案”的评论中得出结论。总之,与任何类类型一样,std::initializer_list有一个编译器提供了演绎指南[over.match.class.deduct]第1.3节。
从假设的构造函数C(C)派生出一个额外的函数模板,称为复制演绎候选。
这意味着std::initializer_list具有编译器隐式声明的演绎指南:
template <class T>
initializer_list (initializer_list <T>) -> initializer_list <T>;当使用非空的初始化程序列表参数来推断此演绎指南的T时,标准的下列规则被应用到[temp.deduct.call]§1
如果从P中删除引用和cv-限定符给出了一些P‘和N的std::初始化器_ list 或P‘n,并且参数是一个非空的初始化程序列表(dcl.init.list),那么将独立地对初始化程序列表的每个元素执行推导,并将P’作为单独的函数模板参数类型P‘i和ith初始化器元素作为相应的参数。
因此,应该将T推导为int,这样类模板参数推导就会成功。
免责声明:我不是部族的拥护者..。
https://stackoverflow.com/questions/55205176
复制相似问题