【发布时间】:2012-07-16 23:07:11
【问题描述】:
我可以不设置具有可变参数数量的函数的参数数量吗?举个例子:下面的接口可以实现吗?
int sum(...) { ... }
sum(1, 2, 3, 4); // return 10
【问题讨论】:
-
不应该很难设置一个可变参数模板来做到这一点,假设你的编译器支持它们。我会发布一个答案,但我没有这样的编译器来测试我的代码。
我可以不设置具有可变参数数量的函数的参数数量吗?举个例子:下面的接口可以实现吗?
int sum(...) { ... }
sum(1, 2, 3, 4); // return 10
【问题讨论】:
传统的variadic functions 很混乱,而且不是类型安全的,但在C++11 中,您可以使用variadic templates 和(编译时)递归干净地做到这一点:
// Base case for recursion
template <typename T>
inline T sum(T n) {
return n;
}
// Recursive case
template <typename T, typename... Args>
inline T sum(T n, Args... args) {
return n + sum(args...);
}
由于它是一个模板,因此它适用于定义了 operator+ 的任何类型:
std::cout << sum(1, 2, 3) << std::endl; // Prints 6
std::cout << sum(3.14, 2.72) << std::endl; // Prints 5.86
但是,由于递归模板函数的返回类型仅取自第一个参数,如果在一次调用中混合不同的参数类型,您会得到令人惊讶的结果:sum(2.5, 2) 按预期返回 4.5,但 sum(2, 2.5) 返回2 因为返回类型是int,而不是double。如果您想花哨,可以使用新的alternative function syntax 指定返回类型是n + sum(args...) 的自然类型:
// Recursive case
template <typename T, typename... Args>
inline auto sum(T n, Args... args) -> decltype(n + sum(args...)) {
return n + sum(args...);
}
现在 sum(2.5, 2) 和 sum(2, 2.5) 都返回 4.5。
如果您的实际逻辑比求和更复杂,并且您不希望它内联,您可以使用内联模板函数将所有值放入某种容器中(例如 std::vector 或 std::array ) 并将其传递给非内联函数以在最后完成真正的工作。
【讨论】:
decltype(n + sum(args...)) 的返回类型没有编译——它抱怨找不到匹配的模板。我尝试了一些东西,但没有花很多时间。
sum 的末尾尝试了那个确切的代码,它工作得很好:inline auto sum (T n, Args... args) -> decltype (n + sum(args...))
您可能希望通过编写函数来获取类似 vector<int> 的内容,您将使用花括号初始化列表动态构建它:
int sum(std::vector<int> const &n) {
return std::accumulate(begin(n), end(n), 0);
}
如果数字可能是(例如)浮点数,您可能希望将其编写为模板:
template <class T>
T sum(std::vector<T> const &n) {
return std::accumulate(begin(n), end(n), T());
}
无论哪种方式,您调用它的方式都会略有不同:
int x = sum({1,2,3,4});
警告:此功能是最近才添加到 C++ 中的,因此一些编译器(例如 VC++)还不支持它——尽管其他编译器(例如 g++ 4.7+)支持。
【讨论】:
template<std::size_t N> int sum(const std::array<int, N>& n) { ... }
std::array 不会重载构造函数来获取初始化列表。相反,您可以使用sum<3>({{2, 3, 5}});
不,你不能。
只是不要使用可变参数。他们吸收了所有可以想象的时尚,完全不值得任何人花时间。
【讨论】:
C++ 可变参数函数必须知道它传递了多少(以及什么类型)的参数。例如,printf 的格式字符串告诉它期望什么额外的参数。
您的 sum 无法知道它是 4 个整数还是 10 个整数。您可以将第一个参数设为长度:
int sum(int howmany, ...) { ... }
所以函数知道后面有多少个整数。但实际上你应该只传递一个数组(或向量,如果你感觉 C++'y)
【讨论】:
有多种方法可以解决您的问题。我会介绍几个:
方法一: - 创建一系列重载求和函数以满足您的需求。
缺点 -代码膨胀
这可以通过使用 headers 制作多个函数来实现:
int sum(int a);
int sum(int a, int b);
int sum(int a, int b, int c);
等等……
方法二: - 创建一个带有链表的自定义类,并传入一个指向链表头部的指针。假设您不知道要传入的数据量,这可能是您在这种情况下的最佳做法。
函数头:
int sum(LinkedList *headPointer);
方法三: - 传入一个变量数组
函数头:
int sum(int input[]);
方法四: - 创建一个带有自动设置变量的函数
函数头:
int sum(int a=0, int b=0, int c=0, int d=0,... int n=0);
【讨论】: