Elsaの技術日記(徒然なるままに)

主に自分で作ったアプリとかの報告・日記を記載

MENU

C++でラムダ式を用いたコールバック関数作成

今回はラムダ関数を用いてC++でコールバック関数を作成していきたいと思います!!
クラス間でコールバック関数を用いてメンバ変数に値をSet/Getしてみたかったので調べてみたところ、
便利そうな方法を見つけたので備忘録としてまとめることに。



ラムダ式とは?

ラムダ式とは、
簡易的な関数オブジェクトをその場で定義するための機能になります。

例えば、

#include <stdio.h>

int main(){
        auto add = [](int a,int b){
                return a + b;
        };
        int result = add(3,5);
        printf("%d \n", result);

        return 0;
}

をビルド⇒実行すると、
resultには3+5の結果である8が格納されます。
ラムダ式は、

auto add = [](int a,int b){
       return a + b;
};

というような形式で書かれます。
意味合いとしては、
「int型のパラメータを2つとり、それらを足し合わせたint型オブジェクトを返す関数オブジェクト」を定義している。
となります。

さらに、ラムダ式の外側の変数を使用する場合には、「キャプチャ」という機能を利用します。
[ ]にどの変数をどのようにキャプチャするかを示します。
例えば、

#include <stdio.h>

int main(){
        int x = 3;
        auto chgval = [&]{x = 1;};
        chgval();

        auto addfive = [=]{ return x + 5;};
        
        int result = addfive();
        printf("%d \n", result);

        return 0;
}

といったコードをビルド⇒実行するとresultに6が格納されます。

これは、

auto chgval = [&]{x = 1;};

ラムダ式の外部で定義したxを1に置き換え、

auto addfive = [=]{ return x + 5;};

を実行するとxに格納された1と5が足し合わされた6が返る式になります。

ラムダ式を用いたコールバック関数

では早速ラムダ式を用いてコールバック関数を作成していきます。
今回はClassAとClassBを作成し、ClassBからClassAへコールバック関数を用いて値をセットしに行くコードを作成します。
まず各コードですがClassA、ClassBそれぞれこちらのようになります。

ClassA.hpp

#include <stdio.h>
#include "ClassB.hpp"

class hogeA{
private:
    int NumA;
    int NumB;
    hogeB m_hogeB = hogeB();
public:
    hogeA(){
        NumA = 0;
        NumB = 0;
    }
    void DoingFunc();
    void SetNumber(int a,int b);
    int GetNumberA(){return NumA;}
    int GetNumberB(){return NumB;}
};

ClassA.cpp

void hogeA::DoingFunc(){
    m_hogeB.Set_HogeA([](int a,int b){
        SetNumber(a,b);
    });
}

void hogeA::SetNumber(int a,int b){
    NumA = a;
    NumB = b;
}

ClassB.hpp

#include <stdio.h>
#include <functional>

class hogeB{
    typedef std::function<void(int,int)> FUNC_POINTER;
    FUNC_POINTER p;
    
public:
    void Set_HogeA(const FUNC_POINTER &func);
    void Set_func();
};

classB.cpp

#include <stdio.h>
#include "ClassB.hpp"

void hogeB::Set_HogeA(const FUNC_POINTER &func){
    p = func;
}

void hogeB::Set_func(){
    p(1,2);
}

まずはClassBに関してですが、

void hogeB::Set_HogeA(const FUNC_POINTER &func){
    p = func;
}

でコールバックをセットする関数を用意します。
FUNC_POINTER ですが、

typedef std::function<void(int,int)> FUNC_POINTER;
FUNC_POINTER p;

と定義しております。

次にClassAですが、
先ほどのラムダ式を用いて、

void hogeA::DoingFunc(){
    m_hogeB.Set_HogeA([&](int a,int b){
        SetNumber(a,b);
    });
}

というようにClassB側にコールバック関数として
SetNumber(a,b);
をセットします。

コールバック関数を使っても旨味の無い処理になってしまいますが、、、
試しにこちらのコードを作成し実行してみます。

int main(){
    hogeA m_hogeA = hogeA();
    hogeB m_hogeB = hogeB();
    
    printf("hogeA:%d \n", m_hogeA.GetNumberA());
    printf("hogeB:%d \n", m_hogeA.GetNumberB());
    printf("============================ \n");
    m_hogeA.DoingFunc();
    m_hogeB.Set_func();

    printf("hogeA:%d \n", m_hogeA.GetNumberA());
    printf("hogeB:%d \n", m_hogeA.GetNumberB());
    printf("============================ \n");
}

結果は下記の通りになるかと思います。

hogeA:0
hogeB:0
============================
hogeA:1
hogeB:2
============================

これは、

m_hogeA.DoingFunc();

でClassBにClassAで定義したSet関数をコールバック関数として定義し、

m_hogeB.Set_func();

によりコールバック関数を用いてClassBからClassAのメンバ変数にSet関数を用いて値(1,2)をセットしたことによります。

■最後に

今回はラムダ式を用いてコールバック関数を作成してみました。
ラムダ式を用いると結構簡単にコールバック関数作成できて便利。