ラムダ式と同じことをラムダ式を使わずに書いてみる。
まずはラムダを使った例
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
//vector の中から find_int を見つける
void test(std::vector<int>& v, int find_int)
{
auto find = std::find_if(v.begin(), v.end(), [&](int i) { return i == find_int; }); //ここでfind_intへの参照をキャプチャしている
if (find != v.end()) {
std::cout << find_int << " FOUND!!\n";
}
else {
std::cout << find_int << " NOT FOUND!!\n";
}
}
int main()
{
std::vector<int> v{1,2,3,4,5};
test(v, 3);
test(v, 9);
}
これを、ラムダを使わずに書くと・・・
void test2(std::vector<int>& v, int find_int)
{
struct Pred {
int& find_int; //これがキャプチャ!
bool operator() (int i) {
return i == find_int;
}
};
Pred pred {find_int};
auto find = std::find_if(v.begin(), v.end(), pred);
if (find != v.end()) {
std::cout << find_int << " FOUND!!\n";
}
else {
std::cout << find_int << " NOT FOUND!!\n";
}
}
つまりラムダ式とは、その場で無名の構造体を作ってoperator()を実装し、関数オブジェクトとしてインスタンス化したもの。
キャプチャされた変数は、関数オブジェクト内にある別のメモリ領域に保持される。
よって、参照やポインタでキャプチャしたものは、その関数オブジェクトが実際に呼ばれる際に、無効になっている可能性があるので注意が必要。
上記の例では、std::find_ifが即座に関数オブジェクトを呼ぶので問題ないが、タスクキューのような後から呼ばれるパターンでは、注意。(参照だから安全ということもない・・・!)
実行できるサンプル:
http://cpp.sh/94hzk