是否有使用 lambda 语法定义递归 constexpr 函数的便捷方法?我找到了一种通过分配给函数指针的不方便的方法constexpr,但我想要一种方法来减少输入并且不更改 lambda 的类型。
以普通方式创建递归 constexpr 函数非常简单。特别是,从 C++11 开始支持使用可能包含三元运算符的单个表达式。
constexpr double factorial2(double x) {
return (x < 0) ? 0 : \
(x == 0) ? 1 : \
/*otherwise*/ (x * factorial2(-1 + x));
}
Run Code Online (Sandbox Code Playgroud)
不太清楚如何使用 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));
};
Run Code Online (Sandbox Code Playgroud)
Clang 会接受这一点,godbolt 上的 GCC 9.2 也会接受。
// 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("%f\n", x);
}
Run Code Online (Sandbox Code Playgroud)
并运行它:
$ rm -f ./a.out && clang++-7 -std=c++17 foo.cpp && ./a.out
10888869450418351940239884288.000000
Run Code Online (Sandbox Code Playgroud)
本节只是一个附录,解释了为什么我决定使用函数指针而不是其他东西。
通过 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));
};
Run Code Online (Sandbox Code Playgroud)
错误:
bar.cpp:7:31: error: variable 'factorial' declared with deduced type 'auto' cannot appear in its own initializer
/*otherwise*/ (x * factorial(-1 + x));
Run Code Online (Sandbox Code Playgroud)
2)使用std::function。
这不起作用,因为std::functiona 是非文字类型。显然。
// 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("%f\n", x);
}
Run Code Online (Sandbox Code Playgroud)
失败并显示错误消息:
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...)>
Run Code Online (Sandbox Code Playgroud)
由于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);
};
Run Code Online (Sandbox Code Playgroud)
(外部) lambda 是一个“闭包类型”,它变成了“文字”并且constexpr仅在 C++17 中可用(因此这不适用于 C++14)。
PS - 我稍微简化了你的阶乘函数并使用整数,因为恕我直言,双打的使用只会分散问题的注意力。
| 归档时间: |
|
| 查看次数: |
107 次 |
| 最近记录: |