[英]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.