我试图理解名为"variadic"的C++ 11特性.看看这个简单的代码:
#include <iostream>
using namespace std;
template<typename T, typename... Args>
T adder(T first, Args... args) {
  return first + adder(args...);
}
int main() {
  int c = adder(1,8,4);
  cout << c << endl;
  cout << "Hello World!" << endl;
  return 0;
}
阅读c ++入门书籍我已经理解它们以递归方式工作,我也看到在递归调用中,args...部分被传递.
我正在使用MinGW 5和QtCreator来测试它.看
好的,要修复我可以调用的太少的参数,adder(first, args...)但现在递归不正确并且程序崩溃了.该怎么办?我无法理解如何做到这一点.
在线查看我发现了一个这样的例子
template <typename T, typename... Rest>
double sum(T t, Rest... rest) {
  return t + sum(rest...);
}
它基本相同.我是否必须使用显式(非模板)返回类型?
Chr*_*n G 10
您需要"stop-recursion-case"(现在不知道正确的名称; UPDATE:它被称为"base-case",感谢Quentin),当模板函数展开时只有一个参数.
#include <iostream>
template<typename T>
T adder(T first) {
  return first;
}
template<typename T, typename... Args>
T adder(T first, Args... args) {
  return first + adder(args...);
}
int main() {
  const int c = adder(1, 8, 4);
  std::cout << c << '\n';
  return 0;
}
使用 C++17折叠表达式,您可以使用单个函数来完成。
您不需要“停止递归案例”。
template<typename... Args>
auto sum(Args... args)
{
    return (args + ...);
}
示例用法,全部打印 42
std::cout << sum(42) << '\n';
std::cout << sum(11, 31.0) << '\n'; // different types
std::cout << sum(3, 4, 5, 6, 7, 8, 9) << '\n';
using namespace std::string_literals;
std::cout << sum("4"s, "2"s) << '\n'; // concatenating strings
你的递归展开如下:
adder(1,8,4)
-> adder<int,int,int>(1,8,4)
-> 1 + adder<int,int>(8,4)
-> 1 + 8 + adder<int>(4)
-> 1 + 8 + 4 + adder<>()
所以Args...每次都变得越来越短,最终是空的.但是你的声明
template<typename T, typename... Args>
T adder(T first, Args... args);
不能用零参数调用,它总是需要至少一个(first).
所以,选项也是
添加该过载不采取零点的参数,如
int adder() { return 0; }
添加一个只带一个参数的重载,它不会尝试继续递归:
template <typename T>
T adder(T t) { return t; }
任何一个会修正错误,但第二个是多好,因为它可以用于任何T,和第一只会增加的东西都是从隐式转换int{0}.
这种模式 - 一般的递归情况加上终止案例来阻止递归 - 在引入可变参数模板之前很常见(我们以前使用类似LISP的递归列表来处理这类事情,这自然会像这样使用递归).
由可变参数模板启用的较新样式利用包扩展来完全避免递归.例如,参见使用的求和示例std::apply