C++でクロージャを作る
C++でもJavascriptなどと同様にクロージャを作る事が出来ます。
環境(状態)を持った関数オブジェクトといった感じで、分かっている人にとってはなんてことはないと思います。
ポイントはlambdaをコピーキャプチャとした上でmutableにすることです。
構造体やクラスを定義してメンバ変数などを用いなくても状態を保持できる関数というのは、上手く使えば便利だと思います。
戻り値型を書くのが面倒なのでC++1yのコードです。
関数の戻り値型をautoだけで済ませられるのは本当に便利ですね。
#include <iostream> auto func() { int x = 0; return [=]() mutable -> void { ++x; std::cout << x << std::endl; }; } int main() { auto f1 = func(); f1(); f1(); f1(); f1(); f1(); auto f2 = func(); f2(); f2(); f2(); f2(); f2(); }
output :
1
2
3
4
5
1
2
3
4
5
追記
実装に不備があったので修正しました。
環境を共有する複数の処理を持ちたい場合、やはりシンプルに引数で場合分けをする方が良さそうです。
参照キャプチャはオブジェクトを複数個生成する場合に使えませんでした。
#include <iostream> auto func () { int x = 0; return [=](std::size_t mode = 0) mutable -> void { switch (mode) { case 1: ++x; std::cout << x << std::endl; break; case 2: --x; std::cout << x << std::endl; break; default: std::cout << x << std::endl; break; } }; } int main() { auto f1 = func(); auto f2 = func(); f1(1); // 1 f2(1); // 1 f1(2); // 0 f2(1); // 2 f1(1); // 1 f2(2); // 1 f1(2); // 0 f2(2); // 0 f1(); // 0 f2(); // 0 }
処理を関数ごとに分けたいとしてもbindなどは、結果的に新しい関数を生成しているので環境が共有されなくなるため使えません。
分けるならf1を生成した後に
auto inc = [&]() { return f1(1); }; auto dec = [&]() { return f1(2); }; inc(); dec();
みたいな感じで分けることになるでしょう。
いずれにせよGCはないので、環境の共有や寿命の管理自体はGCありの言語と異なったアプローチを取る必要があります。