使用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];
}
我尝试过编写推导指南,但每次都会遇到编译器错误。
template <typename T, typename ... U>
mytype(T, U...) -> mytype<1+sizeof...(U)>; // Compiler error
以及我能想到的任何其他指导方针。
是否可以自动推导数组别名的大小?
我正在使用GCC 10.2
是否可以自动推导数组别名的大小?
我认为,通过符合标准的实施应该是可能的。你不必(也不能(再添加任何辅助线。
然而,GCC实现了一组与标准规定不同的规则:
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.
实现者认为;这种简化对于实际使用应该具有相同的效果";。但显然情况并非如此:这种实施在您的情况下失败了,在其他一些情况下也失败了。
作为参考,我将尝试遵循标准并展示mytype
指南是如何生成的。
我们有这样的别名模板声明(别名模板在标准中称为A
(:
template <size_t N>
using mytype = std::array<int, N>;
以及这个来自标准库([array.cons](的推导指南:
template<class T, class... U>
array(T, U...) -> array<T, 1 + sizeof...(U)>;
首先,从推导指南([over.match.class.dexecute]/1(生成一个函数模板(在标准中称为f
(:
template<class T, class... U>
auto f(T, U...) -> array<T, 1 + sizeof...(U)>;
然后,按照【over.match.class.dexecute】/2:
f
的返回类型的模板参数是根据[temp.dreact.type]中的过程从A
的定义类型id中推导出来的,但如果没有推导出所有模板参数,则推导不会失败。
也就是说,我们从std::array<int, N>
推导出array<T, 1 + sizeof...(U)>
中的模板参数。在此过程中,T
被推导为int
;U
是不可推导的,所以它保持原样。
将推导的结果代入函数模板,得到:
template<class T, class... U>
auto g(int, U...) -> array<int, 1 + sizeof...(U)>;
然后,我们生成了一个函数模板f'
。f'
具有与g
相同的返回类型和函数参数类型。(如果f
具有特殊属性,则它们由f'
继承。(但值得注意的是,f'
的模板参数列表由([over.match.class.dexecute]/(2.2(,emphasis mine(:
出现在上述推导中的
A
的所有模板参数(包括其默认模板参数(或(递归地(出现在其默认模板自变量中,然后是未推导出的f
的模板参数(包括其默认模板变量(,否则f'
不是函数模板。
由于N
没有出现在推导中,因此它不包括在模板参数列表中(这是GCC与标准不同的地方(。
此外,f'
还有一个约束([over.match.class.dexecute]/(2.3((:
当且仅当
A
的参数可从返回类型推导(见下文(时,满足。
因此,根据标准,生成的函数模板看起来像:
template<class... U>
requires deducible<array<int, 1 + sizeof...(U)>>
auto f'(int, U...) -> array<int, 1 + sizeof...(U)>;
显然,根据本指南,可以推断出尺寸为1 + sizeof...(U)
。
在下一步中,让我们看看deducible
是如何定义的。
[超过匹配等级扣除]/3:
如果给定类模板,则模板
A
的自变量可以从类型T
推导template <typename> class AA;
对于其模板参数列表是
A
的模板参数列表并且其模板参数表是A
的具有A
的模板参数表的专门化的单个部分专门化([temp.dep.type](,AA<T>
匹配部分专门化。
在我们的情况下,部分专业化将是:
template <size_t N> class AA<mytype<N>> {};
因此deducible
可以声明为:
template <class T> concept deducible = requires { sizeof(AA<T>); };
由于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)>;
其不能推导出CCD_ 38。