簡體   English   中英

嵌套 class 的模板模板參數的可變參數類型模板參數和非類型模板參數如何相互約束?

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

有趣的是, ...TsTs...之間的關系似乎確實存在限制。 例如,所有為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 

這是一個演示

那么...TsTs...在這個結構中如何相互約束的規則是什么?


我在嘗試理解這個問題時遇到了這個問題,它表明 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?
}

每個temp.arg.template#3

當 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM