我可以展开一个参数包并定义一个参数列表吗?

Can I expand a parameters pack and define an arguments list with it?

本文关键字:参数 一个 列表 定义 我可以      更新时间:2023-10-16

从[temp.variadic](工作草案)中,在我看来,参数包可以在定义另一个模板类或函数的参数列表时展开。

考虑以下类:

template<typename... T>
struct S {
    template<T... I>
    void m() {}
};
int main() {
    S<int, char> s;
    // ...
}

目的是捕获用于专门化模板类S的类型,并使用它们为成员方法m定义非类型形参的参数列表(当然,T仅限于几种类型,但这不是问题的参数)。

这是法律法规吗?我可以按照我使用的方式使用参数包吗?还是我误解了标准(非常确定确实是这种情况)?


为了给这个问题添加更多的细节,这里有一些来自主要编译器的实验结果:

  • s.m<0, 'c'>(): clang v3.9编译它,GCC v6.2和GCC v7返回一个错误

  • s.m<0>();: clang v3.9编译它,GCC v6.2返回一个错误,GCC v7用一个ICE停止编译。

  • s.m<>();: clang v3.9, GCC v6.2和GCC v7编译没有错误

至少,编译器似乎和我一样困惑。

模板S的定义和S<int, char>的实例化是有效的

参见[temp.param]/15: "一个模板参数包是参数声明,其类型包含一个或多个未展开的参数包是一个扩展包。"

这意味着template<T ...I>可以表示两种不同的情况之一:如果T是非包类型,那么它声明一个普通参数包,接受任意数量的T。但是,如果T包含一个未展开的参数包,那么在外部模板实例化时,参数声明将被展开为一个参数序列。

第一次调用m是有效的,但是第二次和第三次调用m是错误的

S<int, char>的实例化如下:

template<>
struct S<int, char> {
  template<int I$0, char I$1>
  void m() {}
};

(其中I$0I$1是包I的第一个和第二个片)。

因此(因为I$0I$1都不能从对m的调用中推导出来),s.m<0,'c'>()是有效的,而s.m<0>()s.m<>()是病态的。

相关文章: