std::bind
| ヘッダ <functional> で定義 |
||
template< class F, class... Args > /* 未指定 */ bind( F&& f, Args&&... args ); |
(1) | (C++11以降) (C++20 以降 constexpr) |
template< class R, class F, class... Args > /* 未指定 */ bind( F&& f, Args&&... args ); |
(2) | (C++11以降) (C++20 以降 constexpr) |
関数テンプレートstd::bindは、fに対する転送呼び出しラッパーを生成します。このラッパーを呼び出すことは、引数の一部をargsにバインドしてfを呼び出すことと同等です。
std::is_constructible<std::decay<F>::type, F>::valueがfalseの場合、またはArgs内の任意の型Arg_iに対してstd::is_constructible<std::decay<Arg_i>::type, Arg_i>::valueがfalseの場合、プログラムは不正です。
std::decay<Ti>::typeまたはArgs内の任意の型がMoveConstructibleまたはDestructibleでない場合、動作は未定義です。
目次 |
[編集] パラメータ
| f | - | 一部の引数にバインドされるCallableオブジェクト(関数オブジェクト、関数へのポインタ、関数への参照、メンバ関数へのポインタ、またはデータメンバへのポインタ) |
| args | - | バインドする引数リスト。未バインドの引数は、名前空間std::placeholdersのプレースホルダー_1、_2、_3...で置き換えられます。 |
[編集] 戻り値
型Tが未指定の関数オブジェクトg。std::is_bind_expression<T>::valueはtrueです。以下のメンバを持ちます。
std::bind 戻り値の型
メンバーオブジェクト
std::bindの戻り値の型は、std::forward<F>(f)から構築されたstd::decay<F>::type型のメンバオブジェクトを保持し、args...の各要素に対して、同様にstd::forward<Arg_i>(arg_i)から構築されたstd::decay<Arg_i>::type型のオブジェクトを保持します。
コンストラクタ
std::bindの戻り値の型は、そのすべてのメンバオブジェクト(上記で指定)がCopyConstructibleである場合はCopyConstructibleであり、そうでない場合はMoveConstructibleです。この型は以下のメンバを定義します。
メンバ型
|
(C++20まで) |
メンバー関数 operator()
関数呼び出し式g(u1, u2, ... uM)でgが呼び出されると、以下のように格納されたオブジェクトの呼び出しが行われます。
INVOKE(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN))、またはINVOKE<R>(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN))、ここで、fdはstd::decay<F>::type型の値であり、バインドされた引数v1, v2, ..., vNの値と型は以下で指定されます。
g()への呼び出しで提供される引数の一部が、gに格納されているどのプレースホルダーとも一致しない場合、未使用の引数は評価され破棄されます。
operator()の呼び出しは、基になるINVOKE操作が例外を投げない、または定数部分式である(C++20以降)場合に限り、例外を投げません。operator()は、INVOKE操作が未評価のオペランドとして扱われた場合に適切な形式である場合にのみ、オーバーロード解決に参加します。
gがvolatile修飾されている場合、プログラムは不正です。
いかなる可能な値w1, w2, ..., wNに対してもINVOKE(fd, w1, w2, ..., wN)が有効な式になり得ない場合、動作は未定義です。
[編集] 束縛された引数
格納された各引数arg_iについて、INVOKEまたはINVOKE<R>操作における対応する束縛された引数v_iは次のように決定されます。
[編集] ケース1:参照ラッパー
arg_iがstd::reference_wrapper<T>型(例えば、std::bindの最初の呼び出しでstd::refまたはstd::crefが使用された場合)の場合、v_iはarg_i.get()であり、その型V_iはT&です。格納された引数は、呼び出される関数オブジェクトに参照渡しされます。
[編集] ケース2:バインド式
arg_iが型Tであり、std::is_bind_expression<T>::valueがtrueである場合(例えば、別のstd::bind式がstd::bindの初期呼び出しに直接渡された場合)、std::bindは関数合成を実行します。バインド部分式が返す関数オブジェクトを渡す代わりに、部分式は eagerly に呼び出され、その戻り値が外側のinvokableオブジェクトに渡されます。バインド部分式にプレースホルダー引数がある場合、それらは外側のバインドと共有されます(u1, u2, ...から選択されます)。具体的には、v_iはarg_i(std::forward<Uj>(uj)...)であり、その型V_iはstd::result_of<T cv &(Uj&&...)>::type&&(C++17まで)std::invoke_result_t<T cv &, Uj&&...>&&(C++17以降)です(cv修飾はgと同じです)。
[編集] ケース3:プレースホルダー
arg_iが型Tであり、std::is_placeholder<T>::valueが0でない場合(つまり、std::placeholders::_1, _2, _3, ...のようなプレースホルダーがstd::bindの初期呼び出しの引数として使用された場合)、プレースホルダーによって示される引数(_1の場合はu1、_2の場合はu2など)が呼び出し可能なオブジェクトに渡されます。v_iはstd::forward<Uj>(uj)であり、その型V_iはUj&&です。
[編集] ケース4:通常の引数
それ以外の場合、arg_iは左辺値引数として呼び出し可能なオブジェクトに渡されます。v_iは単純にarg_iであり、その型V_iはT cv &です。ここでcvはgと同じcv修飾です。
[編集] 例外
std::forward<F>(f)からのstd::decay<F>::typeの構築が例外を投げる場合、またはArgs... args内のi番目の型がArg_iでi番目の引数がarg_iである場合、対応するstd::forward<Arg_i>(arg_i)からのstd::decay<Arg_i>::typeのコンストラクタのいずれかが例外を投げる場合にのみ例外を投げます。
[編集] 備考
Callableで説明されているように、非静的メンバ関数へのポインタまたは非静的データメンバへのポインタを呼び出す場合、最初の引数は、メンバがアクセスされるオブジェクトへの参照またはポインタ(std::shared_ptrやstd::unique_ptrなどのスマートポインタを含む)である必要があります。
バインドの引数はコピーまたは移動され、std::refまたはstd::crefでラップされない限り、参照渡しされることはありません。
同じバインド式で重複するプレースホルダー(例えば、複数の_1)は許可されますが、結果は対応する引数(u1)が左辺値または移動不可能な右辺値である場合にのみ正しく定義されます。
[編集] 例
#include <functional> #include <iostream> #include <memory> #include <random> void f(int n1, int n2, int n3, const int& n4, int n5) { std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n'; } int g(int n1) { return n1; } struct Foo { void print_sum(int n1, int n2) { std::cout << n1 + n2 << '\n'; } int data = 10; }; int main() { using namespace std::placeholders; // for _1, _2, _3... std::cout << "1) argument reordering and pass-by-reference: "; int n = 7; // (_1 and _2 are from std::placeholders, and represent future // arguments that will be passed to f1) auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n); n = 10; f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused // makes a call to f(2, 42, 1, n, 7) std::cout << "2) achieving the same effect using a lambda: "; n = 7; auto lambda = [&ncref = n, n](auto a, auto b, auto /*unused*/) { f(b, 42, a, ncref, n); }; n = 10; lambda(1, 2, 1001); // same as a call to f1(1, 2, 1001) std::cout << "3) nested bind subexpressions share the placeholders: "; auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5); f2(10, 11, 12); // makes a call to f(12, g(12), 12, 4, 5); std::cout << "4) bind a RNG with a distribution: "; std::default_random_engine e; std::uniform_int_distribution<> d(0, 10); auto rnd = std::bind(d, e); // a copy of e is stored in rnd for (int n = 0; n < 10; ++n) std::cout << rnd() << ' '; std::cout << '\n'; std::cout << "5) bind to a pointer to member function: "; Foo foo; auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1); f3(5); std::cout << "6) bind to a mem_fn that is a pointer to member function: "; auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum); auto f4 = std::bind(ptr_to_print_sum, &foo, 95, _1); f4(5); std::cout << "7) bind to a pointer to data member: "; auto f5 = std::bind(&Foo::data, _1); std::cout << f5(foo) << '\n'; std::cout << "8) bind to a mem_fn that is a pointer to data member: "; auto ptr_to_data = std::mem_fn(&Foo::data); auto f6 = std::bind(ptr_to_data, _1); std::cout << f6(foo) << '\n'; std::cout << "9) use smart pointers to call members of the referenced objects: "; std::cout << f6(std::make_shared<Foo>(foo)) << ' ' << f6(std::make_unique<Foo>(foo)) << '\n'; }
出力
1) argument reordering and pass-by-reference: 2 42 1 10 7 2) achieving the same effect using a lambda: 2 42 1 10 7 3) nested bind subexpressions share the placeholders: 12 12 12 4 5 4) bind a RNG with a distribution: 0 1 8 5 5 2 0 7 7 10 5) bind to a pointer to member function: 100 6) bind to a mem_fn that is a pointer to member function: 100 7) bind to a pointer to data member: 10 8) bind to a mem_fn that is a pointer to data member: 10 9) use smart pointers to call members of the referenced objects: 10 10
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| LWG 2021 | C++11 | 1. 束縛された引数は fdに転送されていなかった。 2. ケース2において、 V_iの型はstd::result_of<T cv (Uj...)>::type |
1. 転送されるようになった。 2. 次のように変更された。 std::result_of<T cv &(Uj&&...)>::type&& |
[編集] 関連項目
| (C++20)(C++23) |
可変個の引数を順番に関数オブジェクトに束縛する (関数テンプレート) |
| (C++11) |
std::bind 式における未束縛の引数のためのプレースホルダ(定数) |
| (C++11) |
メンバへのポインタから関数オブジェクトを生成する (関数テンプレート) |