std::bindを使うと関数の引数を自由にコントロールできる

相変わらずC++の勉強を続けているが、本日新たにstd::bindというものを目にした。
昔はなかった気がしたので調べてみるとC++11で追加された機能らしい。

std::bindとは

一言でカンタンに言うと関数の引数を束縛する機能。
例えば引数がA,B,Cと3つあるような関数でもstd::bindをすることで、引数が1つだけの関数として呼び出すことができるようになる。

コードとしてはこんな感じ

#include <iostream>
#include <functional>

void test_function(int x, int y, int z)
{
        std::cout << "x:" << x << " y:" << y << " z:" << z << std::endl;
}

int main()
{
    test_function(1, 2, 3); // bindしないとデフォルト3つの引数指定が必要
    // 出力 ⇒ x:1 y:2 z:3     

    auto binded_func = std::bind(test_function, 1, 2, 3);
    binded_func(); // bindしたので引数指定不要
    // 出力 ⇒ x:1 y:2 z:3     

    return 0;
}

std::bindが無い場合だと以下のようにラップした関数を用意して使う等の手間が必要だったが、これが不要なのでラク

static void test_function(int x, int y, int z)
{
        std::cout << "x:" << x << " y:" << y << " z:" << z << std::endl;
}

// C++11以前はわざわざラップ関数を作らないと外から使えなかった
static void wrapped_test_function()
{
    test_function(1, 2, 3);
}

引数の順番変更や部分指定するのもカンタン

引数の省略以外にも、引数の順番変更や一部だけ指定なんかもできる。
std::placeholdersというのがあるのでこれを使用する。

部分省略の場合はこんな感じ

int main()
{
    auto binded_func = std::bind(test_function, std::placeholders::_1,
                                        2,
                                        3);
    binded_func(1); // 第1引数のみ指定、他は固定
    // 出力 ⇒ x:1 y:2 z:3

    return 0;
}

順番入れ替えの場合はこんな感じ。
std::placeholdersの後の数字が引数の何番目かに対応している。

int main()
{
    auto binded_func = std::bind(test_function, std::placeholders::_3,
                                        std::placeholders::_2,
                                        std::placeholders::_1);
    binded_func(1, 2, 3); // test_functionの第1引数が3、第2引数が2、第3引数が1
    // 出力 ⇒ x:3 y:2 z:1

    return 0;
}

クラスのメンバ関数もbindできる

bind対象にできるのはただの関数だけではなく、クラスのメンバ関数も対象にできる。
メンバ関数を指定する場合は、std::bindの2つ目の引数にインスタンスを指定する必要がある。

#include <iostream>
#include <functional>

class Hoge 
{
    public:
        void Display(int x) 
        {
            std::cout << "x:" << x << std::endl;
        }
};

int main()
{
    Hoge hoge;
    auto binded_func = std::bind(&Hoge::Display, hoge, 1); // 2つ目の引数はインスタンスを指定
    binded_func();
    // 出力 ⇒ x:1

    return 0;
}

補足

どうでもよいことだが、g++の場合だとstd::placeholdersの最大は29だった。
30個以上placeholdersで指定はできないらしい。
まぁそんな関数ふつうは無いと思うが。。