为什么这个嵌套的可变参数模板是无效参数?

Why is this nested variadic template an invalid argument?

如果我定义一个接受模板参数的 struct 模板 Bar

template <template <int,bool,char> class>
struct Bar {};

我可以使用 struct 模板实例化它,例如 Zod:

template <int,bool,char> struct Zod {};
Bar<Zod> a;

我也可以使用嵌套的 struct 模板实例化它,例如 JKL:

struct GHI {
  template <int,bool,char>
  struct JKL {};
};
Bar <GHI::JKL> b;

为什么我不能使用 DEF 等嵌套可变参数 struct 模板来实例化 Bar?:

template <typename ...Ts>
struct ABC {
  template <Ts ...>
  struct DEF {};
};

Bar<ABC<int,bool,char>::DEF> c;

G++ 4.9.2 抱怨 type/value 不匹配;而 Clang 3.4.2 的错误报告模板模板参数与其对应的模板模板参数具有不同的模板参数。

就像巴里之前说的:

ABC<int,bool,char>::DEF<4,true,'c'> foo

并尝试在本网站上使用 Coliru 在线编译器 gcc 5.1 c++14 Compiler:

#include <iostream>
 template <template <int,bool,char> class>
struct Bar {};
template <int,bool,char> struct Zod {};

Bar<Zod> a;

struct GHI {
  template <int,bool,char>
  struct JKL {};
};

Bar <GHI::JKL> b;

template <template <typename... Ts> class>
struct Base {};
template<typename... Ts>
struct Floor {};
Base<Floor> c;

template <typename... Ts>
struct ABC {
  template <Ts... val>
  struct DEF {};
};
ABC<int,bool,char>::DEF<4,true,'c'> foo;

我搜索了一下,找到了这个模板参数列表。

包扩展可能出现在模板参数列表中:

 template<typename... T> struct value_holder
{
    template<T... Values> // expands to a non-type template parameter 
    struct apply { };     // list, such as <int, char, int(&)[5]>
};

我在 运行 代码编译器中测试了一些东西: http://en.cppreference.com/w/cpp/language/parameter_pack 但我也在 visual studio 2013 年找到了这个省略号和可变参数模板: https://msdn.microsoft.com/en-us/library/dn439779.aspx

让我们给DEF的参数包起个名字方便参考:

template <typename ...Ts>
struct ABC {
  template <Ts ... Values>
  struct DEF {};
};

这里的关键点是 [temp.param]/p15,Ts... Values TsTs 的包扩展参数包的声明 Values.

If a template-parameter is [...] a parameter-declaration that declares a parameter pack (8.3.5), then the template-parameter is a template parameter pack (14.5.3). A template parameter pack that is a parameter-declaration whose type contains one or more unexpanded parameter packs is a pack expansion.

由于DEF采用非类型参数包,它与不采用包的模板模板参数不匹配([temp.arg.template]/p3):

A template-argument matches a template template-parameter P when each of the template parameters in the template-parameter-list of the template-argument’s corresponding class template or alias template A matches the corresponding template parameter in the template-parameter-list of P. Two template parameters match if they are of the same kind (type, non-type, template), for non-type template-parameters, their types are equivalent (14.5.6.1), and for template template-parameters, each of their corresponding template-parameters matches, recursively. When P’s template-parameter-list contains a template parameter pack (14.5.3), the template parameter pack will match zero or more template parameters or template parameter packs in the template-parameter-list of A with the same type and form as the template parameter pack in P (ignoring whether those template parameters are template parameter packs).

可以肯定的是,Values 对于包来说相当奇怪 - 对于 ABC 的每个特化,Values 必须包含固定数量的参数 - 但在当前规则下它仍然是一个包,所以包的规则适用。