在显式构造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发布于 2019-03-17 13:43:38
Clang是唯一正确的编译器。是的,真的。
当编译器看到没有模板参数的模板名时,它必须查看模板的演绎指南,并将它们应用到大括号列表中的参数中。initializer_list没有任何显式的演绎指南,所以它使用可用的构造函数。
initializer_list拥有的唯一可公开访问的构造函数是它的复制/移动构造函数和它的默认构造函数。从大括号中的列表创建std::initializer_list不是通过可公开访问的构造函数完成的。它是通过列表初始化完成的,这是一个只编译的进程。只有编译器才能执行构建一个步骤所需的顺序。
考虑到所有这些,应该不可能在initializer_lists上使用CTAD,除非您正在从现有列表中进行复制。最后一部分可能是其他编译器在某些情况下如何使它工作的。在演绎方面,它们可以将大括号中的列表推演为initializer_list<T>本身,而不是应用[over.match.list]的一系列参数,因此演绎指南会看到副本操作。
发布于 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
复制相似问题