LoginSignup
6
6

More than 5 years have passed since last update.

【C++】ラムダ式を紐解く

Posted at

ラムダ式と同じことをラムダ式を使わずに書いてみる。

まずはラムダを使った例

#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

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6