繁体   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