![](/img/trans.png)
[英]Template template parameter with mixed type and non-type variadic parameters
[英]How do variadic type template parameters and non-type template parameters of the template template parameter of a nested class constrain each other?
考虑以下结构: S
是一个 class 模板,带有模板类型参数的可变参数包...Ts
。 class 包含一个嵌套的 class 模板N
,它有一个模板模板参数C
。 C
本身是用一组非类型模板参数的可变参数包模板化的,这些参数的类型正好是Ts...
template <typename ...Ts>
struct S
{
template <template <Ts...> typename C>
struct N
{
C<42> c;
};
};
GCC 拒绝c
的声明:
error: expansion pattern '<anonymous>' contains no parameter packs
C<42> c;
^
我不知道这个诊断意味着什么,我猜这是一个 GCC 错误。
Clang 接受这种结构,也接受合理的实例化,例如:
template<int> struct W {};
S<int>::N<W> w; // ok, makes sense
当然,声明C<42> c;
它本身对用作参数C
的参数的模板施加了约束,即使C
中的Ts...
只是auto...
也是必需的。 例如Ts...
的第一个参数必须是可以从int
隐式转换的类型。 此外, Ts...
中的其余参数(如果有)必须具有默认值。
template<bool(*)()> struct X1 {};
S<int>::N<X1> x1; // error: value of type 'int' is not implicitly convertible to 'bool (*)()'
template<int, char> struct X2 {};
S<int>::N<X2> x2; // error: too few template arguments for class template 'X2'
有趣的是, ...Ts
和Ts...
之间的关系似乎确实存在限制。 例如,所有为S
指定的 arguments 现在必须是有效的非类型模板参数类型:
template<int> struct Y {};
S<int, void>::N<Y> y; // error: a non-type template parameter cannot have type 'void'
另一方面,Clang 也接受看似不兼容的S
的实例化,以及C
的非类型模板参数:
template<int> struct Z {};
S<bool(*)(), bool>::N<Z> z; // ok ?? But why? both number and type of 'Ts' is different
这是一个演示。
那么...Ts
和Ts...
在这个结构中如何相互约束的规则是什么?
我在尝试理解这个问题时遇到了这个问题,它表明 MSVC 也不接受代码。
For your primary question (nested class with non-type template arguments dependent on template arguments in outer class) this is a bug in GCC, #86883 (See comment #3 )
我认为Clang
是不对的。
temp.param#15
作为参数声明的模板参数包,其类型包含一个或多个未扩展的参数包,是包扩展。
对于嵌套模板 class N
的模板模板参数,即template <Ts...> typename C
,其中Ts...
是一个包实例化,其规则如下:
每个 Ei 是通过实例化模式并用其第 i 个元素替换每个包扩展参数来生成的。 在实例化的上下文中,这样的元素解释如下:
- 如果包是模板参数包,则元素是相应类型(类型或非类型)的模板参数,指定模板参数的类型或值;
所以,对于这个例子S<bool(*)(), bool>::N<Z> z;
, 实例化Ts...
将给出一个列表bool(*)(), bool
。 因此,问题可以简化为:
template<template<bool(*)(), bool> class C>
struct Nested{};
template<int> struct Z {};
int main(){
Nested<Z> z; // is well-formed?
}
当 P 至少与模板参数 A 一样特化时,模板参数匹配模板模板参数 P。
参数Z
是否与参数C
匹配? 根据这个规则temp.arg.template#4
A template template-parameter P is at least as specialized as a template template-argument A if, given the following rewrite to two function templates, the function template corresponding to P is at least as specialized as the function template corresponding to A according to the function 模板的部分排序规则。 给定一个发明的 class 模板 X,其模板参数列表为 A(包括默认的 arguments ):
- 两个 function 模板中的每一个都具有相同的模板参数,分别为 P 或 A。
- Each function template has a single function parameter whose type is a specialization of X with template arguments corresponding to the template parameters from the respective function template where, for each template parameter PP in the template parameter list of the function template, a corresponding template argument AA形成了。 如果 PP 声明了一个参数包,那么 AA 就是包扩展 PP... ([temp.variadic]); 否则,AA 是 id 表达式 PP。
如果重写产生了无效类型,那么 P 至少不像 A 那样专门化。
这意味着,我们有一个发明的模板 class X 具有以下形式:
template<int>
struct InventedX{};
然后, A
的重写 function 模板具有以下形式:
template<int N>
auto iventend_function(X<N>);
而P
的重写 function 模板具有以下形式:
template<bool(*A)(), bool B>
auto invented_function(X<A,B>) // invalid type for X<A,B>
因此, P 至少不像 A 那样专业。 因此A
不能与P
匹配。 所以, S<bool(*)(), bool>::N<Z> z;
应该是不正确的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.