Arj*_*ais 11 c++ aggregate-initialization template-aliases c++20 deduction-guide
使用 C++20,可以为别名模板生成推导准则(请参阅https://en.cppreference.com/w/cpp/language/class_template_argument_deduction 上的“别名模板的推导”部分)。然而,我无法让它们使用聚合初始化语法。在这种情况下,似乎没有生成别名的扣除指南。
看这个例子:
#include <array>
template <size_t N>
using mytype = std::array<int, N>;
// Deduction guideline ???
int main() {
// mytype error_object = {1, 4, 7}; // ERROR
mytype<3> object = {1, 4, 7}; // OK, but I have to manually specify the size.
return object[0];
}
Run Code Online (Sandbox Code Playgroud)
我曾尝试编写演绎指南,但每次都会出现编译器错误。
template <typename T, typename ... U>
mytype(T, U...) -> mytype<1+sizeof...(U)>; // Compiler error
Run Code Online (Sandbox Code Playgroud)
以及我能想到的任何其他准则。
甚至可以自动推导出数组别名的大小吗?
我正在使用 GCC 10.2
甚至可以自动推导出数组别名的大小吗?
我相信符合标准的实现应该是可能的。您不需要(也不能)添加更多指南。
但是,GCC 实施的规则与标准规定的不同:
Run Code Online (Sandbox Code Playgroud)This implementation differs from [the specification] in two significant ways: 1) We include all template parameters of A, not just some. 2) The added constraint is same_type instead of deducible.
实现者认为“这种简化对于实际使用应该具有相同的效果”。但显然情况并非如此:此实现无法在您的情况下工作,而在其他一些情况下则无法使用ICE。
作为参考,我将尝试遵循标准并展示如何mytype生成指南。
我们有这个别名模板声明(别名模板A在标准中被调用):
template <size_t N>
using mytype = std::array<int, N>;
Run Code Online (Sandbox Code Playgroud)
以及来自标准库([array.cons])的推导指南:
template<class T, class... U>
array(T, U...) -> array<T, 1 + sizeof...(U)>;
Run Code Online (Sandbox Code Playgroud)
首先,f从推导指南([over.match.class.deduct]/1)生成一个函数模板(在标准中调用):
template<class T, class... U>
auto f(T, U...) -> array<T, 1 + sizeof...(U)>;
Run Code Online (Sandbox Code Playgroud)
然后,根据[over.match.class.deduct]/2:
的返回类型的模板参数
f从推导定义型-ID的A按照[temp.deduct.type]的过程,不同的是,如果不是所有的模板参数推导演绎不会失败。
也就是说,我们在array<T, 1 + sizeof...(U)>from 中推导出模板参数std::array<int, N>。在这个过程中,T推导出为int;U不可推导,因此保持原样。
将推导的结果代入函数模板,得到:
template<class T, class... U>
auto g(int, U...) -> array<int, 1 + sizeof...(U)>;
Run Code Online (Sandbox Code Playgroud)
然后,我们生成一个函数模板f'。f'具有与 相同的返回类型和函数参数类型g。(如果f有特殊属性,它们由 继承f'。)但值得注意的是,模板参数列表f'由([over.match.class.deduct]/(2.2),强调我的)组成:
出现在上述推导中或(递归地)在其默认模板参数中的
A(包括其默认模板参数)的所有模板参数,后跟f未推导的模板参数(包括其默认模板参数),否则f'不是功能模板。
由于N没有出现在推导中,所以没有包含在模板参数列表中(这是GCC与标准不同的地方)。
此外,f'还有一个约束([over.match.class.deduct]/(2.3)):
当且仅当 的参数
A可从返回类型推导出(见下文)时才满足。
因此,根据标准,生成的函数模板如下所示:
template<class... U>
requires deducible<array<int, 1 + sizeof...(U)>>
auto f'(int, U...) -> array<int, 1 + sizeof...(U)>;
Run Code Online (Sandbox Code Playgroud)
显然,大小可以推导出为 1 + sizeof...(U)根据本指南。
在下一步中,让我们看看如何 deducible定义。
如果给定类模板,
A则称模板的参数可从类型推导出TRun Code Online (Sandbox Code Playgroud)template <typename> class AA;具有单个部分特化,其模板参数列表是 的,
A并且模板参数列表是 的特化A,模板参数列表是A([temp.dep.type]),AA<T>匹配部分特化。
在我们的例子中,部分专业化将是:
template <size_t N> class AA<mytype<N>> {};
Run Code Online (Sandbox Code Playgroud)
所以deducible可以声明为:
template <class T> concept deducible = requires { sizeof(AA<T>); };
Run Code Online (Sandbox Code Playgroud)
由于N可从 推导出1 + sizeof...(U),array<int, 1 + sizeof...(U)>始终是mytype<N>(又名std::arrray<int, N>)的有效匹配项,因此deducible<array<int, 1 + sizeof...(U)>>始终满足约束。
因此,根据标准,生成的指南是可行的,可以推断出大小。
相比之下,GCC 生成:
template<class... U, size_t N>
requires same_type<array<int, 1 + sizeof...(U)>, mytype<N>>
auto f_(int, U...) -> array<int, 1 + sizeof...(U)>;
Run Code Online (Sandbox Code Playgroud)
...这是无法推断的N。