我有以下小的可变参数模板,它应该划分一系列数字。据我了解,这是一个粗略的草图,如果我打电话给divide(20, 2, 2)
- >会发生什么? 20/ 2 / 2
。显然它并没有那么好,因为我得到的答案是20 ......当只有两个论点时,它工作正常。
#include <iostream>
template<class first_t>
auto divide(const first_t &first)
{
return first;
}
template<class first_t, class... rest_t>
double divide(const first_t &first, const rest_t&... rest)
{
return first / divide(rest...);
}
int main()
{
std::cout << divide(20, 2, 2); //should print 5
std::cin.get();
}
答案 0 :(得分:11)
divide
的实施基本上扩展为以下内容:
divide(20, 2, 2)
- &gt; return 20 / divide(2,2)
- &gt; return 20 / 1
你要么想要从左到右分开如下:
template<class first_t, class second_t, class... rest_t>
double divide(const first_t& first, const second_t& second, const rest_t&... rest)
{
return divide(first/second, rest...);
}
或按上述评论中的建议乘以其余的除数。
作为一个副节点,C ++ 17将包含一个新的https://www.parse.com/apps/quickstart?app_id=iraven#parse_push/ios/swift/existing语法,允许你这样编写它:
template<class... value_t>
auto divide(const value_t&... values) {
return (... / values);
// and (values / ...) would replicate your original implementation :)
}
对于尺寸为1的参数包,它将自动执行The Right Thing™。
答案 1 :(得分:0)
能够使用cout
或printf
来理解执行流程对于诊断问题非常有帮助。下面是一个懒惰的方法,用于检测代码以诊断问题。
#include <iostream>
template<class first_t>
double divide(const first_t &first)
{
std::cout << "Came to 1\n";
return first;
}
template<class first_t, class... rest_t>
double divide(const first_t &first, const rest_t&... rest)
{
std::cout << "Came to 2\n";
auto res = divide(rest...);
std::cout << "res: " << res << "\n";
return 1.0*first / res;
}
int main()
{
std::cout << divide(20, 2, 2) << std::endl;
return 0;
}
输出:
Came to 2
Came to 2
Came to 1
res: 2
res: 1
20
答案 2 :(得分:0)
正如@ melak47所说,你在递归调用中最终折叠了。要向左折叠,请评估结果并将结果转发到列表的其余元素。如果你想在没有递归的情况下进行折叠,你也可以只扩展可变参数(保证按顺序)并通过std::accumulate
运行值。
template <typename... Values>
double divide(double dividend, Values... divisors) {
std::initializer_list<double> div_list = {double(divisors)...};
return std::accumulate(std::begin(div_list), std::end(div_list), dividend,
std::divides<>());
}
如果你想避免重复划分,你也可以通过乘法然后除法来除数除数。
template <typename... Values>
double divide(double dividend, Values... divisors) {
std::initializer_list<double> div_list = {double(divisors)...};
return dividend / std::accumulate(std::begin(div_list), std::end(div_list),
1.0, std::multiplies<>());
}