甚至可以自动推导出数组别名的大小吗?
我相信符合标准的实现应该是可能的。您不需要(也不能)添加更多指南。
但是,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.
实施者认为“这种简化对于实际使用应该具有相同的效果”。但显然情况并非如此:此实现在您的情况下无法正常工作,而ICE 在其他一些情况下则无法正常工作。
作为参考,我将尝试遵循标准并展示如何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.deduct]/1 )生成一个函数模板(f
在标准中调用):
template<class T, class... U>
auto f(T, U...) -> array<T, 1 + sizeof...(U)>;
然后,根据[over.match.class.deduct]/2:
的返回类型的模板参数是根据[temp.deduct.type] 中的过程从定义类型 idf
推导出来的,但如果不是所有模板参数都被推导出来,则推导不会失败。A
也就是说,我们从 中推导出模板array<T, 1 + sizeof...(U)>
参数std::array<int, N>
。在这个过程中,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.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)>;
显然,可以1 + sizeof...(U)
根据本指南推断大小。
下一步,让我们看看deducible
是如何定义的。
[over.match.class.deduct]/3:
如果给定类模板,A
则称模板的参数可从类型推导出T
template <typename> class AA;
具有单个偏特化,其模板形参列表是 ofA
并且其模板实参列表是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)
,因此始终是(aka )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)>;
...无法推断N
。