lambda 的深度递归
Deep recursion of lambda
>我有一个由N级循环组成的程序。但是N不是固定的,所以我拿模板来帮忙。以下是逻辑。
#include <type_traits>
void do_something1() {}
void do_something2() {}
enum Case { one, two };
struct loop {
template<int N, Case case_, typename Lambda>
std::enable_if_t < (0 < N) > func(Lambda&& visit) const {
//return directly in some cases, so complexity is not a problem
func<N - 1, one>([&visit] {
do_something1();// depend on the results of func<N - 1, one>
visit();
});
func<N - 1, two>([&visit] {
do_something2();// depend on the results of func<N - 1, two>
visit();
});
}
template<int N, Case case_, typename Lambda>
std::enable_if_t < (0 == N) > func(Lambda&& visit) const {
visit();
}
};
int main() {
loop{}.func<32, one>([] {});
return 0;
}
但是,由于深度递归,这不会编译。在我看来,它是内联和 func 中的两个分支导致问题。那么,有没有一种有效的方法来解决这个问题?
内联可以解决运行时的复杂性。"提前返回"还解决了运行时的复杂性。但是,编译器错误是因为编译时的复杂性。即使是无法访问的代码也必须编译。
如果编译器内联此代码,则此代码具有极大的复杂性。两个分支都将是内联的,这意味着f<31>
的// return early
检查在f<32>
中内联两次,f<30>
的// return early
检查在f<31>
中内联两次,因此在f<32>
中内联4次,因此f<0>
将内联约40亿次。没有像样的编译器应该有问题;它应该跳过内联。
简单的解决方案是删除Case
(无论如何都不使用它)并N
成为常规变量。更复杂的方法是在运行时检查变量 N 是否具有一些小的常量值 Nc,然后才调用函数的模板化版本。通过选择 Nc,可以限制模板实例化深度。
相关文章:
- 通过递归进行因子分解
- 递归函数计算序列中的平方和(并输出过程)
- 使用递归的数组的最小值.这是怎么回事
- 使用后序遍历递归的深度优先搜索会产生意外输出
- 由于深度递归而导致堆栈溢出
- 5000+ 深度递归时函数堆栈溢出
- OpenMP:即使在深度极限的情况下,递归任务也比顺序慢
- 可变参数模板实例化中的无限递归,试图构建任意深度的树状结构
- lambda 的深度递归
- C++递归函数,调用当前深度
- 递归的最大深度是多少?
- 查找最大递归深度
- 如何跳出一些深度递归的函数并直接返回结果
- 如何跟踪递归深度
- 如何改进此模式所需的模板递归深度
- 递归深度切断策略:并行快速排序
- 具有合成和继承属性的深度递归qi语法(解析器)
- 为什么这超过了递归模板的最大深度
- 递归模板实例化超出了最大深度 256
- 深度优先搜索或回溯递归查找字谜/拼字板中所有可能的字母组合