通过 lambda 定义的 constexpr 递归函数
constexpr recursive function defined via lambda
有没有一种方便的方法可以使用lambda语法定义递归constexpr函数?我通过分配给constexpr
函数指针找到了一种不方便的方法,但我想要一种用更少的类型并且不更改 lambda 类型的方式来做到这一点。
以普通方式制作递归 constexpr 函数非常简单。 特别是,自 C++11 年以来一直支持使用可能包含三元运算符的单个表达式。
constexpr double factorial2(double x) {
return (x < 0) ? 0 :
(x == 0) ? 1 :
/*otherwise*/ (x * factorial2(-1 + x));
}
不太清楚如何使用 lambda 语法执行此操作。我将在下面包括我的各种失败尝试,但我找到了一种通过使用constexpr
函数指针而不是auto
作为我正在使用 lambda 初始化的变量的类型注释来制作 constexpr 函数的方法。
typedef double (* factorial_t)(double);
constexpr factorial_t factorial = [](double x) constexpr noexcept -> double {
return (x < 0) ? 0 :
(x == 0) ? 1 :
/*otherwise*/ (x * factorial(-1 + x));
};
Clang会接受这一点,GCC 9.2 on godbolt 也会接受这一点。
// foo.cpp
#include <cstdio>
typedef double (* factorial_t)(double);
constexpr factorial_t factorial = [](double x) constexpr noexcept -> double {
return (x < 0) ? 0 :
(x == 0) ? 1 :
/*otherwise*/ (x * factorial(-1 + x));
};
int main() {
constexpr auto x{factorial(27)};
printf("%fn", x);
}
并运行它:
$ rm -f ./a.out && clang++-7 -std=c++17 foo.cpp && ./a.out
10888869450418351940239884288.000000
本节只是一个附录,解释了为什么我决定使用函数指针而不是其他东西。
尝试通过 lambda 生成递归 constexpr 函数失败。
1( 使用auto
正如这个有点老的问题中所解释的,允许使用您在 lambda 中定义的事物的名称,但不能很好地与类型推断交互。答案建议使用std::function
auto factorial = [](double x) constexpr noexcept -> double {
return (x < 0) ? 0 :
(x == 0) ? 1 :
/*otherwise*/ (x * factorial(-1 + x));
};
错误:
bar.cpp:7:31: error: variable 'factorial' declared with deduced type 'auto' cannot appear in its own initializer
/*otherwise*/ (x * factorial(-1 + x));
2(使用std::function
。
这不起作用,因为std::function
是非文本类型。显然地。
// bar.cpp
#include <cstdio>
#include <functional>
constexpr std::function<double(double)> factorial = [](double x) constexpr noexcept -> double {
return (x < 0) ? 0 :
(x == 0) ? 1 :
/*otherwise*/ (x * factorial(-1 + x));
};
int main() {
constexpr auto x{factorial(27)};
printf("%fn", x);
}
失败并显示错误消息:
bar.cpp:5:41: error: constexpr variable cannot have non-literal type 'const std::function<double (double)>'
constexpr std::function<double(double)> factorial = [](double x) constexpr noexcept -> double {
^
/usr/bin/../lib/gcc/aarch64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/functional:1834:11: note: 'function<double (double)>' is
not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors
class function<_Res(_ArgTypes...)>
由于Pedro Melendez的一篇博客文章,有一个技巧,它绕过了直接递归,并且可以在constexpr上下文中使用。感谢@HolbyBlackCat的参考和想法。
constexpr auto factorial = [](int n) {
auto factorial_impl = [](int n, auto& factorial_ref) {
if(n <= 1) { return 1; }
return n * factorial_ref(n-1, factorial_ref);
};
return factorial_impl(n,factorial_impl);
};
在GodBolt上看到它。
(外部(lambda 是一种"闭包类型",它变成了"文字",只能在 C++17 中与constexpr
一起使用(因此这不适用于 C++14(。
PS - 我稍微简化了你的阶乘函数并使用整数,因为恕我直言,使用双精度只是分散了问题的注意力。
- 递归函数计算序列中的平方和(并输出过程)
- 如何在Elixir中调用递归函数并行
- 递归函数有效,但无法记忆
- 为什么我的递归函数按降序打印,然后按升序打印?
- 为什么递归函数的最终输出是 5?
- 有没有办法使用递归函数找到数组中最小值的 INDEX?C++
- 如何将记忆应用于此递归函数?
- 如何从递归函数中完全返回,该函数给出了每个函数结果的累积相加?
- 无穷大而循环时具有递归函数
- 即使没有调用这个递归函数,它是如何工作的?
- 如何使此递归函数从给定的起始位置返回最小的整数?
- 此递归函数的每次迭代的值存储在哪里?
- 可以清除递归函数中的变量吗?
- 如何在递归函数调用中返回当前函数值
- 递归函数 c++ 的复杂性
- 这个递归函数有什么作用?运行时的复杂性是多少?
- 任何人都可以查明我的递归函数中的错误吗?
- 递归函数的返回类型推导
- 通过 lambda 定义的 constexpr 递归函数
- Constexpr递归函数是否使用If ConstexPR