std::bind関数の利用方法を解説します。また関連するstd::placeholdersの活用方法や、廃止が決まったbind1st関数/bind2nd関数からの移行方法についても解説します。
- std::bind(引数の束縛と部分適用の実現)
- std::placeholders(プレースホルダの利用)
- bind1st/bind2ndの代替として利用する
std::bind
std::bind
関数は指定の関数オブジェクトに対して引数を束縛する関数です。戻り値は新たな関数オブジェクトです。
これよって引数の値を特定の関数へ部分適用することが可能になります。部分適用後の関数オブジェクトは任意のタイミングで呼び出すことが可能となります。
auto f = std::bind(toupper, 'a');
f(); // 'A'
// 関数呼び出し`toupper('a')`が行われる
std::bind(toupper, 'a')
は、実引数の事前評価が行われてしまう点を除けば、ラムダ式による[] { return toupper('a'); }
と同等の役割を果たすものとなります。bind関数は部分適用を実現したり、特定の処理を任意のタイミングで実行可能にするための用途として活用できます。
std::placeholders
std::placeholders
によるプレースホルダをbind関数の引数として指定することで、任意の引数を受け取る関数オブジェクトを生成させることも可能となります。
auto g = std::bind(toupper, std::placeholders::_1);
g('a'); // 'A'
_1
で一つ目の引数であることを明示しています。二つ目の引数が必要な場合は続けて_2
を引数に指定します。
auto h = std::bind(printf, "%s %d",
std::placeholders::_1,
std::placeholders::_2);
h("shop", 99); // "Shop 99"
bindの結果をbindに渡す
bind関数が生成した関数オブジェクトをさらにbind関数に渡すようなことも可能となります。
auto i = std::bind(printf, "%s %d",
std::placeholders::_1,
std::placeholders::_2);
auto j = std::bind(i, "shop", std::placeholders::_1);
j(99); // "Shop 99"
引数を指定の順序で束縛する
引数の適用順序をプレースホルダの指定順序でもって明示することも可能です。
auto k = std::bind(printf, "%d%d%d%d",
1, std::placeholders::_2,
3, std::placeholders::_1);
k(4, 2); // "1234"
std::functionへの変換
bind関数はstd::functionへの変換も可能です。
std::function<int(int)> l = std::bind(toupper, 'a');
この機能によって、bind関数が返す関数オブジェクトを特定の関数の引数や戻り値として使用したり、特定のデータ構造で保持したりすることが可能になります。
bind1st/bind2ndの代替として利用する
以前はbindと同等の関数としてbind1st
やbind2nd
という関数が存在していましたが、使い勝手が悪く(指定の関数に対してunary_functionクラスへの準拠が必要となる等)、また現在(C++11)ではbinder1st/binder2ndクラスと共に非推奨の機能となっています(C++17で廃止される予定)。
bind1st
bind1st関数は二項演算関数の第一引数に値を束縛します。
std::bind1st(std::minus<int>(), 3)(2); // 1 = (3 - 2)
bind2nd
bind2nd関数は二項演算関数の第二引数に値を束縛します。
std::bind2nd(std::minus<int>(), 3)(2); // -1 = (2 - 3)
代替処理
これらの関数(bind1st, bind2nd)は廃止が決まっているため、bind関数やラムダ式で置き換える必要があります。
// bind1stの代替処理
std::bind(std::minus<int>(), 3, std::placeholders::_1)(2); // 1 = (3 - 2)
// bind2ndの代替処理
std::bind(std::minus<int>(), std::placeholders::_1, 3)(2); // -1 = (2 - 3)
ラムダ式によるbind1st/bind2ndの代替
もっとも、ラムダ式を用いたほうが簡潔な記述になる場合もあるため、余裕があれば、ラムダ式への移行を検討するのも良いでしょう。
[](int b) { return 3 - b; }(2); // 1 = (3 - 2)
[](int a) { return a - 3; }(2); // -1 = (2 - 3)