使用未扩展的参数包作为模板模板参数的非类型模板参数的类型是否合法?

Is it legal to use an unexpanded parameter pack as the type of a template template parameter's non-type template parameter?

gcc 和 clang 不同意以下代码是否应该编译:

template <typename... Args>
struct tuple {};

template <typename>
struct Test;

template <
    typename... Types,
    template <Types> typename... Outer, // XXX
    Types... Inner
>
struct Test<tuple<Outer<Inner>...>> {};

template <long T> struct O1 {};
template <unsigned T> struct O2 {};

Test<tuple<O1<1>, O2<2>>> test;

clang 接受代码,推导 Types = {long, unsigned}, Outer = {O1, O2}, Inner={1L, 2U}。从结构上看,这似乎是正确的。

gcc 拒绝推导失败的代码。有趣的是,如果将 O2 更改为采用 long 非类型模板参数,它 确实 接受,这对我来说似乎不一致。它表明如果 Types = {long, long} 可以扩展类型,但如果 Types = {long, unsigned}.

则不能

但是,我不清楚哪个编译器是正确的标准。核心问题是:在表示为XXX的那一行,将参数包作为模板模板参数的非类型模板参数的类型是否有效?它应该像 clang 声称的那样扩展吗?

无效 因为:

a type parameter pack cannot be expanded in its own parameter clause.

[temp.param]/17开始:

If a template-parameter is a type-parameter with an ellipsis prior to its optional identifier or is a parameter-declaration that declares a pack ([dcl.fct]), then the template-parameter is a template parameter pack. A template parameter pack that is a parameter-declaration whose type contains one or more unexpanded packs is a pack expansion. ... A template parameter pack that is a pack expansion shall not expand a template parameter pack declared in the same template-parameter-list.

因此请考虑以下无效示例:

template<typename... Ts, Ts... vals> struct mytuple {}; //invalid

上面的例子无效,因为模板类型参数包Ts不能在自己的参数列表中展开

出于同样的原因,您的代码示例无效。