【问题标题】:Can I expand a parameters pack and define an arguments list with it?我可以扩展一个参数包并用它定义一个参数列表吗?
【发布时间】:2017-02-01 13:57:18
【问题描述】:

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

考虑以下类:

template<typename... T>
struct S {
    template<T... I>
    void m() {}
};

int main() {
    S<int, char> s;
    // ...
}

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

这是合法的代码吗?我可以按照我使用的方式使用参数包还是我误解了标准(很确定确实如此)?


为了给问题添加更多细节,以下是一些主要编译器的实验结果:

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

【问题讨论】:

  • 是的,它是有效的,甚至可以是空的:stackoverflow.com/questions/32540178/…
  • GCC 在可变参数模板方面并不聪明。
  • @JohannesSchaub-litb 不应该因此拒绝s.m&lt;0&gt;(); 吗?在这种情况下,两个编译器都出错了?
  • 其他 SO 用户告诉我,语义是“T...I”意味着 T 被扩展,“I”成为 int 和 char 值的包。 (即异构非类型模板参数包)。我不明白为什么 clang 接受的“I”参数少于两个参数。话虽如此,这么多年过去了,我仍然认为我还没有完全理解这个特殊案例的规则。
  • @JohannesSchaub-litb 实际上我只是在阅读它们。因此this 代码也有效吗?如果你能花一分钟时间,我会接受你的回答。我猜它几乎来自同一个问题。

标签: c++ gcc clang language-lawyer variadic-templates


【解决方案1】:

模板S的定义和S&lt;int, char&gt;的实例化都是有效的。

参见 [temp.param]/15:“模板参数包是一个 parameter-declaration,其类型包含一个或多个未扩展的参数包是包扩展。”

这意味着template&lt;T ...I&gt; 可以表示两种不同的东西之一:如果T 是非包类型,则它声明一个普通参数包,接受任意数量的Ts。但是,如果T 包含未扩展的参数包,则在实例化外部模板时,参数声明将改为扩展为参数序列。

您对m 的第一次调用有效,但您对m 的第二次和第三次调用格式错误

S&lt;int, char&gt; 的实例化如下所示:

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

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

因此(因为I$0I$1 都不能从对m 的调用中推导出来),s.m&lt;0,'c'&gt;() 有效,但s.m&lt;0&gt;()s.m&lt;&gt;() 格式不正确。

【讨论】:

  • 我已经向两个编译器打开了问题,提供了几乎相同的细节。谢谢你。这同样适用于this 问题吗?
  • 为了完整起见,here 是 GCC 的问题,here 是铿锵的问题。如果需要,请随时添加详细信息。论点你比我熟练多了!!
  • 感谢您的回答。所以包展开后,我会认为包不再是参数包了。但是,在成员函数f中,我还是可以说t...。考虑到当时的T 已经扩展并且成员函数模板特化应该看起来像void f(int t) 而不是void f(&lt;int&gt; pack),这是否应该被禁止?我想,即函数参数包的实例化/扩展会产生一系列参数。
  • 这是我说的代码:coliru.stacked-crooked.com/a/12f94d8c9ae763c0。如果即使在成员函数专业化中它仍然是一个包,而不仅仅是在 temploid 定义中,我无法理解为什么 template&lt;typename ...T&gt; struct A { void f(); void f(T...t); }; 被拒绝。函数参数包的存在是函数参数类型列表的一部分。
  • SO:要么它始终是一个包,并且在函数模板专业化中它可以像在 coliru 测试用例或完美转发场景中那样扩展,但 void f(); void f(T... t) 应该是一个有效的重载,或者它一旦模板被实例化,它就不再是一个包了。然后我真的不明白我们如何扩展t...,因为它的大小只有在包含模板被实例化之后才知道。到时候已经不是pack了,应该不能再扩展了。
猜你喜欢
  • 1970-01-01
  • 2022-01-04
  • 1970-01-01
  • 2019-08-31
  • 2011-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多