c++ - 参数包必须在参数列表的末尾......何时以及为什么?

标签 c++ templates c++11 variadic-templates

如果参数列表绑定(bind)到一个类,我不明白参数包必须位于参数列表末尾的原因,而如果参数列表是成员方法声明的一部分,则放宽约束。

换句话说,这个编译:

class C {
    template<typename T, typename... Args, typename S>
    void fn() { }
};

以下一项没有:

template<typename T, typename... Args, typename S>
class C { };

为什么第一种情况被认为是正确的,而第二种情况则不是?
我的意思是,如果它是合法的语法,不应该在这两种情况下都适用吗?

要清楚,真正的问题是我定义了一个类似于以下的类:

template<typename T, typename... Args, typename Allocator>
class C { };

将分配器类型作为最后一种类型将不胜感激,但我可以以某种方式解决它(无论如何,如果您有建议,我们将不胜感激,也许您的建议比我的优雅得多!)。
也就是说,我得到了错误:

parameter pack 'Args' must be at the end of the template parameter list

所以,我只是想完全理解为什么它在某些情况下被接受,但在其他一些情况下却不是。

Here是一个类似的问题,但它只是解释了如何解决问题,这对我来说很清楚。

最佳答案

它对函数模板有效,但只有当参数推导可以帮助编译器解析模板参数时,你的函数模板示例实际上是无用的,因为

template<typename T, typename... Args, typename S> void fn() { }
int main() { fn<int, int, int>(); }
test.cpp: In function 'int main()':
test.cpp:2:32: error: no matching function for call to 'fn()'
 int main() { fn<int, int, int>(); }
                                ^
test.cpp:1:57: note: candidate: template<class T, class ... Args, class S> void fn()
 template<typename T, typename... Args, typename S> void fn() { }
                                                         ^
test.cpp:1:57: note:   template argument deduction/substitution failed:
test.cpp:2:32: note:   couldn't deduce template parameter 'S'
 int main() { fn<int, int, int>(); }

编译器无法确定哪些模板参数属于参数包,哪些属于S。实际上就像@T.C.指出它实际上应该是一个语法错误,因为以这种方式定义的函数模板永远无法实例化。

一个更有用的函数模板是这样的

template<typename T, typename... Args, typename S> void fn(S s) { }

因为现在编译器能够明确地将函数参数 s 与模板类型 S 匹配,具有 S 的副作用总是被推导出来 - 第一个之后的所有显式模板参数都将属于 Args

这些都不适用于(主)类模板,不会推导出参数并且明确禁止:

来自草案 n4567

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4567.pdf

[温度参数]/11

[...]If a template-parameter of a primary class template or alias template is a template parameter pack, it shall be the last template-parameter.[...]

(如果它们被推导出来,就会像函数模板示例中那样模棱两可)。

关于c++ - 参数包必须在参数列表的末尾......何时以及为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34940875/

相关文章:

c++ - 什么时候临时用作命名对象的初始值设定项被销毁?

C++任意函数反序列化

c++ - 为什么对重载函数的调用不明确?

c++ - 左值的正确引用

c++使用memcpy在数组内复制

c++ - "address not from malloc()"使用电子围栏出错

c++ - 多个文件困难的模板

java - 如何在 IntelliJ IDEA 中创建具有默认文件名的模板?

c++ - 错误 : cannot convert ‘<lambda(double)>’ to ‘double (*)(double)’

c++ - 为什么我会收到 "invalid conversion from ' Queue*/Stack *' to ' int'"错误消息?