1: 2021-10-14 (木) 10:56:28 takatsuka[4] [5] | 現: 2021-10-14 (木) 11:46:26 takatsuka[4] [6] | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | 準備中 | + | 無名関数(ラムダ)を再帰呼び出ししたくなることが稀によくあると思います。 |
+ | |||
+ | そこで昨今ならば不動点コンビネータが定石かと思います。 | ||
+ | |||
+ | #prettify{{ | ||
+ | int fibonacci(int n) { | ||
+ | const auto Y = [](auto f) { | ||
+ | return [=](auto... args) { | ||
+ | return f(f, args...); | ||
+ | }; | ||
+ | }; | ||
+ | auto f = Y([](auto f, int n)->int { | ||
+ | return n < 2 ? n : f(f, n - 1) + f(f, n - 2); | ||
+ | }); | ||
+ | return f(n); | ||
+ | } | ||
+ | |||
+ | int main() { | ||
+ | std::cout << fibonacci(10) << std::endl; | ||
+ | } | ||
+ | }} | ||
+ | |||
+ | Yコンビネータなる実装です。関数の引数で自分自身が与えられています。 | ||
+ | これでまったく問題ありません。解決です。 | ||
+ | |||
+ | がしかし唯一の弱点としては C++14 以上が必要になることです。 | ||
+ | |||
+ | ですのでココでは C++14 未満でも使えるローテクな手段 | ||
+ | ''その場にローカルクラス(構造体)と関数を定義し再帰呼び出し'' です。 | ||
+ | #prettify{{ | ||
+ | int fibonacci(int n) { | ||
+ | struct F { | ||
+ | static int f(int n) { | ||
+ | return n < 2 ? n : f(n - 1) + f(n - 2); | ||
+ | } | ||
+ | }; | ||
+ | return F::f(n); | ||
+ | } | ||
+ | }} | ||
+ | |||
+ | |||
+ | コレの弱点としては | ||
+ | |||
+ | ・ラムダではないのでキャプチャが使えない!(これはイタイ) | ||
+ | ・つまり無名関数ではない!(・・・なので記事タイトルに偽りアリとのご指摘あればスミマセン) | ||
+ | ・見てくれがダサい!(・・・個人の感想です) | ||
+ | |||
+ | などありますが、関数の外(スコープ)を汚すこともなく、 | ||
+ | std::function も使わず(計ってはいませんが)遅くもなさそうで、 | ||
+ | 実はコレで十分な場合も多そうです。 | ||
+ | |||
+ | ちなみに constexpr もイケます。 | ||
+ | #prettify{{ | ||
+ | int rev(int n){ | ||
+ | struct F { | ||
+ | static constexpr int f(int n) { | ||
+ | return n < 2 ? n : f(n - 1) + f(n - 2); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | switch (n) { | ||
+ | case F::f(3): return 3; | ||
+ | case F::f(4): return 4; | ||
+ | case F::f(5): return 5; | ||
+ | } | ||
+ | return -1; | ||
+ | } | ||
+ | }} | ||
+ | ~ | ||
+ | ~ | ||
+ | C++ は14や17になって色々と出来ることが増えてきましたが、 | ||
+ | ローカルクラス自体は C++11 未満のコンパイラ、C++03 とかでも使えるハズなので有難く思うことがあるかもしれません。 | ||
+ | |||
+ | なお、以下サイトの記事 "C++のラムダで再帰する" はとても充実しており大変参考になりました。 | ||
+ | https://koturn.hatenablog.com/entry/2018/06/10/060000 | ||
+ | |||
+ | その他、サイトで色々な情報を提供されている方々にも感謝です。 | ||
+ | ありがとうございました。 |
(This host) = https://thinkridge.com