【发布时间】:2021-03-08 22:53:54
【问题描述】:
考虑以下结构:S 是一个类模板,其中包含模板类型参数...Ts 的可变参数包。该类包含一个嵌套类模板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 的所有指定参数现在必须是有效的非类型模板参数类型:
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
这是demo。
那么...Ts 和Ts... 在这个结构中如何相互约束的规则是什么?
我在尝试理解 question 时遇到了这个问题,它表明 MSVC 也不接受代码。
【问题讨论】:
-
一个有趣的问题是,当命名为
C时,默认参数是否应该应用于Z。如果是,那么检查N更难;如果不是,那么 gcc 是对的。 -
@Yakk-AdamNevraumont 我不确定我是否理解为什么默认参数很重要。如果
N中的声明是C<1> n;,那么b也被接受,X没有默认参数。 -
即使没有预期的默认值,gcc 也会抱怨Demo。
-
@cigien 如果默认参数未“通过”,那么您的模板仅对空包有效,我上次检查时这是非法的(格式错误,ndr)。
C<1>case 没有这个问题。 -
@cigien 此外,仅包含数字
42的参数包也是格式错误的,ndr - 这就是所谓的毛巾规则。 (这是个玩笑,因为在互联网上传达幽默如果不明确是很困难的)
标签: c++ templates language-lawyer variadic-templates non-type