std::bind
ヘッダ <functional> で定義
|
||
(1) | ||
template< class F, class... Args > /*unspecified*/ bind( F&& f, Args&&... args ); |
(C++11以上) (C++20未満) |
|
template< class F, class... Args > constexpr /*unspecified*/ bind( F&& f, Args&&... args ); |
(C++20以上) | |
(2) | ||
template< class R, class F, class... Args > /*unspecified*/ bind( F&& f, Args&&... args ); |
(C++11以上) (C++20未満) |
|
template< class R, class F, class... Args > constexpr /*unspecified*/ bind( F&& f, Args&&... args ); |
(C++20以上) | |
関数テンプレート bind
は f
に対する転送呼び出しラッパーを生成します。 このラッパーの呼び出しは args
に束縛された引数のいくつかを使用して f
を呼ぶことと同等です。
目次 |
[編集] 引数
f | - | いくつかの引数に束縛される Callable なオブジェクト (関数オブジェクト、関数ポインタ、関数参照、メンバ関数ポインタまたはデータメンバポインタ) |
args | - | 名前空間 std::placeholders のプレースホルダー _1, _2, _3... で置き換えた未束縛引数を持つ、束縛する引数のリスト
|
[編集] 戻り値
std::is_bind_expression<T>::value == true である未規定な型 T
の関数オブジェクト。 以下のメンバを持ちます。
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()
bind
の以前の呼び出しによって取得されたオブジェクト g
が関数呼び出し式 g(u1, u2, ... uM) で呼ばれた場合、 std::invoke(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN)) によって行われたかのように、格納されているオブジェクトの呼び出しが行われます。 ただし fd
は std::decay_t<F> 型の値であり、束縛引数 v1, v2, ..., vN
の値および型は以下のように決定されます。
- 格納されている引数
arg
が std::reference_wrapper<T> 型の場合 (例えばbind
の呼び出しで std::ref または std::cref が使用された)、上のstd::invoke
呼び出しの引数vn
はarg.get()
であり、型Vn
はT&
です。 格納されている引数は呼び出された関数オブジェクトに参照渡しされます。 - 格納されている引数
arg
が std::is_bind_expression<T>::value == true であるような型T
の場合 (例えば別のbind
式がbind
の呼び出しに直接渡された)、bind
は関数合成を行います。 bind 部分式が返す関数オブジェクトを渡す代わりに、その部分式が先行して呼び出され、その戻り値が外側の呼び出し可能なオブジェクトに渡されます。 bind 部分式が何らかのプレースホルダー引数を持っている場合、それらは外側の bind と共有されます (u1, u2, ...
から取り出されます)。 具体的には、上のstd::invoke
呼び出しの引数vn
はarg(std::forward<Uj>(uj)...)
であり、その型Vn
は std::result_of_t<T cv &(Uj&&...)>&& です (cv 修飾はg
のものと同じです)。 - 格納されている引数
arg
が std::is_placeholder<T>::value != 0 であるような型T
の場合 (std::placeholders::_1, _2, _3, ...
のようなプレースホルダーがbind
の呼び出しの引数として使用された)、そのプレースホルダーの表す引数 (_1
の場合はu1
、_2
の場合はu2
、など) が呼び出し可能なオブジェクトに渡されます。 上のstd::invoke
呼び出しの引数vn
は std::forward<Uj>(uj) であり、対応する型Vn
は Uj&& です。 - そうでなければ、普通の格納されている引数
arg
が呼び出し可能なオブジェクトに左辺値引数として渡されます。 上のstd::invoke
呼び出しの引数vn
は単純にarg
であり、対応する型Vn
はT cv &
です。 ただし cv はg
のものと同じ cv 修飾です。
g()
の呼び出しに供給された引数のいくつかが g
に格納されているいずれのプレースホルダーによってもマッチされない場合、未使用の引数は評価され破棄されます。
g
が volatile 修飾されている場合 (つまり cv 修飾子が volatile または const volatile のいずれかの場合)、動作は未定義です。
[編集] 例外
std::forward<F>(f) からの std::decay<F>::type の構築が例外を投げる場合、または std::decay<Arg_i>::type に対する対応する std::forward<Arg_i>(arg_i) からのコンストラクタのいずれかが例外を投げる場合にのみ、例外を投げます。 ただし Arg_i
は Args... args
のi番目の型で arg_i
はi番目の引数です。
[編集] ノート
Callable で説明されているように、非静的メンバ関数ポインタまたは非静的データメンバポインタを呼び出すとき、最初の引数はアクセスされるメンバを持つオブジェクトへの参照またはポインタ (std::shared_ptr および std::unique_ptr のようなスマートポインタも含みます) でなければなりません。
束縛される引数はコピーまたはムーブされます。 std::ref または std::cref でラップされていなければ、参照渡しされることはありません。
同じ bind 式で複数のプレースホルダーを使用する (例えば _1
を複数回使用する) ことができますが、結果は対応する引数 (u1
) が左辺値またはムーブ可能でない右辺値である場合にのみ well-defined です。
[編集] 例
#include <random> #include <iostream> #include <memory> #include <functional> 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; // _1, _2, _3... のため。 // 引数の順序変更と参照渡しをデモンストレーションします。 int n = 7; // (_1 と _2 は std::placeholders のもので、 f1 に渡される未来の引数を表します) auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n); n = 10; f1(1, 2, 1001); // 1 は _1 によって束縛され、 2 は _2 によって束縛され、 1001 は未使用です。 // f(2, 42, 1, n, 7) の呼び出しを行います。 // プレースホルダを共有するネストした bind 部分式。 auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5); f2(10, 11, 12); // f(12, g(12), 12, 4, 5); の呼び出しを行います。 // 一般的なユースケース: 乱数エンジンに分布を束縛します。 std::default_random_engine e; std::uniform_int_distribution<> d(0, 10); auto rnd = std::bind(d, e); // e のコピーが rnd に格納されます。 for(int n=0; n<10; ++n) std::cout << rnd() << ' '; std::cout << '\n'; // メンバ関数に引数を束縛します。 Foo foo; auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1); f3(5); // データメンバにポインタを束縛します。 auto f4 = std::bind(&Foo::data, _1); std::cout << f4(foo) << '\n'; // 参照先のオブジェクトのメンバを呼ぶためにスマートポインタを使用することもできます。 std::cout << f4(std::make_shared<Foo>(foo)) << '\n' << f4(std::make_unique<Foo>(foo)) << '\n'; }
出力:
2 42 1 10 7 12 12 12 4 5 1 5 0 2 0 8 2 2 10 8 100 10 10 10
[編集] 関連項目
(C++20) |
可変個の引数を順番通りに関数オブジェクトに束縛します (関数テンプレート) |
(C++11) |
std::bind 式におけるバインドされない引数のためのプレースホルダ (定数) |
(C++11) |
メンバポインタから関数オブジェクトを作成します (関数テンプレート) |