可变模板除法器
Variadic template divider
本文关键字:除法器 更新时间:2023-10-16
我有下面的小变分模板,它应该用来划分一系列数字。据我所知,这是一个粗略的草图,如果我调用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();
}
divide
的实现基本上扩展到以下内容:
divide(20, 2, 2)
->return 20 / divide(2,2)
->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将包含一个新的fold表达式语法,这将允许您这样写:
template<class... value_t>
auto divide(const value_t&... values) {
return (... / values);
// and (values / ...) would replicate your original implementation :)
}
哪个会做正确的事™对于自动大小为1的参数包。
能够使用cout
或printf
来理解执行流程对诊断问题非常有帮助。下面是一个懒人的方法来检测你的代码来诊断问题。
#include <iostream>
template<class first_t>
double divide(const first_t &first)
{
std::cout << "Came to 1n";
return first;
}
template<class first_t, class... rest_t>
double divide(const first_t &first, const rest_t&... rest)
{
std::cout << "Came to 2n";
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
正如@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<>());
}
相关文章:
- 在没有太多条件句的情况下,我如何避免被零除
- 引用一个已擦除类型(void*)的指针
- 擦除while循环中迭代的元素
- 在运行时处理类型擦除的数据-如何不重新发明轮子
- C++擦除(如果存在)
- 在映射擦除c++期间执行循环的次数
- 移除前面有空格的前2个字符串
- 为什么擦除方法会影响结束方法
- 我应该将除 .cpp 以外的其他文件添加到 git 中吗?
- 如何修复我的最大公约数代码?它适用于除零和零以外的所有数字
- C++ 字符串类擦除成员函数的时空复杂性
- 类型擦除的std::function与虚拟函数调用的开销
- C++14 中unordered_map矢量和擦除删除成语的奇怪行为
- 替换 C++17 中移除的绑定 1st
- 移除和删除与向量中的条件匹配的指针
- C++ 擦除函数中需要澄清
- 循环挂起迭代的 std::擦除 on std::list
- 对于某些输入,使用逐位操作完成的2除法器的舍入幂失败
- 可变模板除法器
- C++双字符数组除法器