std:: bind
|
ヘッダーで定義
<functional>
|
||
|
template
<
class
F,
class
...
Args
>
/* unspecified */ bind ( F && f, Args && ... args ) ; |
(1) |
(C++11以降)
(C++20以降constexpr) |
|
template
<
class
R,
class
F,
class
...
Args
>
/* unspecified */ bind ( F && f, Args && ... args ) ; |
(2) |
(C++11以降)
(C++20以降constexpr) |
関数テンプレート
std::bind
は
f
の転送呼び出しラッパーを生成します。このラッパーを呼び出すことは、
f
をその引数の一部が
バインドされた
状態で呼び出すことと等価です。
std::
is_constructible
<
std::
decay
<
F
>
::
type
, F
>
::
value
が
false
である場合、または
std::
is_constructible
<
std::
decay
<
Arg_i
>
::
type
, Arg_i
>
::
value
が
false
である場合(
Args
内の任意の型
Arg_i
について)、プログラムは不適格(ill-formed)です。
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::
decay
<
F
>
::
type
型のメンバオブジェクトを保持します。これは
std::
forward
<
F
>
(
f
)
から構築されます。また、
args...
の各引数に対して1つずつ、
std::
decay
<
Arg_i
>
::
type
型のオブジェクトを保持します。これらは同様に
std::
forward
<
Arg_i
>
(
arg_i
)
から構築されます。
コンストラクタ
std::bind
の戻り値型は、そのすべてのメンバオブジェクト(上記で指定)が
CopyConstructible
である場合はCopyConstructibleであり、そうでない場合は
MoveConstructible
となります。この型は以下のメンバを定義します:
メンバ型
|
(C++20まで) |
メンバー関数
operator()
g が関数呼び出し式 g ( u1, u2, ... uM ) で呼び出されるとき、格納されたオブジェクトの呼び出しが行われます。あたかも以下のように
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 修飾されている場合、プログラムは不適格です。
もし
INVOKE
(
fd, w1, w2, ..., wN
)
が、いかなる可能な値
w1
,
w2
, ...,
wN
に対しても有効な式になり得ない場合、動作は未定義です。
バインド引数
格納された各引数
arg_i
について、
INVOKE
または
INVOKE<R>
操作における対応する束縛引数
v_i
は以下のように決定されます:
ケース1: リファレンスラッパー
arg_i
が型
std::
reference_wrapper
<
T
>
の場合(例えば、
std::ref
または
std::cref
が
std::bind
の初期呼び出しで使用された場合)、
v_i
は
arg_i.
get
(
)
となり、その型
V_i
は
T&
となります:保存された引数は参照によって呼び出される関数オブジェクトに渡されます。
Case 2: バインド式
arg_i
の型が
T
であり、かつ
std::
is_bind_expression
<
T
>
::
value
が
true
である場合(例えば、別の
std::bind
式が初期の
std::bind
呼び出しに直接渡された場合)、
std::bind
は関数合成を実行します:バインド部分式が返す関数オブジェクトを渡す代わりに、部分式が積極的に呼び出され、その戻り値が外側の呼び出し可能オブジェクトに渡されます。バインド部分式がプレースホルダー引数を持つ場合、それらは外側のバインドと共有されます(
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
と同じです)。
Case 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&&
となります。
Case 4: 通常の引数
それ以外の場合、
arg_i
は左辺値引数として呼び出し可能オブジェクトに渡されます:
v_i
は単に
arg_i
であり、その型
V_i
は
T
cv
&
となります。ここで
cv
は
g
と同じcv修飾です。
例外
std::
decay
<
F
>
::
type
の構築が
std::
forward
<
F
>
(
f
)
からの変換で例外を送出する場合、または
std::
decay
<
Arg_i
>
::
type
のいずれかのコンストラクタが対応する
std::
forward
<
Arg_i
>
(
arg_i
)
からの変換で例外を送出する場合にのみ例外を送出する。ここで
Arg_i
はi番目の型、
arg_i
は
Args... args
内のi番目の引数を表す。
注記
Callable で説明されているように、非静的メンバ関数へのポインタまたは非静的データメンバへのポインタを呼び出す際には、最初の引数はメンバがアクセスされるオブジェクトへの参照またはポインタ( std::shared_ptr や std::unique_ptr などのスマートポインタを含む)でなければなりません。
bindへの引数はコピーまたはムーブされ、参照で渡されることはありません。ただし、 std::ref または std::cref でラップされた場合を除きます。
同じbind式内での重複プレースホルダー(例えば複数の _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; // _1, _2, _3... 用 std::cout << "1) 引数の順序変更と参照渡し: "; 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) への呼び出しを行います std::cout << "2) 同じ効果をラムダを使用して達成する方法: "; n = 7; auto lambda = [&ncref = n, n](auto a, auto b, auto /*未使用*/) { f(b, 42, a, ncref, n); }; n = 10; lambda(1, 2, 1001); // f1(1, 2, 1001) の呼び出しと同じ std::cout << "3) ネストされた 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::cout << "4) RNGを分布にバインドする: "; 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'; std::cout << "5) メンバ関数へのポインタにバインド: "; Foo foo; auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1); f3(5); std::cout << "6) メンバ関数へのポインタである mem_fn にバインドする: "; 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) データメンバへのポインタへのバインド: "; auto f5 = std::bind(&Foo::data, _1); std::cout << f5(foo) << '\n'; std::cout << "8) データメンバへのポインタである mem_fn にバインドする: "; 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) 参照されるオブジェクトのメンバーを呼び出すにはスマートポインタを使用する: "; std::cout << f6(std::make_shared<Foo>(foo)) << ' ' << f6(std::make_unique<Foo>(foo)) << '\n'; }
出力:
1) 引数の順序変更と参照渡し: 2 42 1 10 7 2) ラムダを使用して同じ効果を達成: 2 42 1 10 7 3) ネストされたbind部分式はプレースホルダを共有: 12 12 12 4 5 4) 分布を持つRNGをバインド: 0 1 8 5 5 2 0 7 7 10 5) メンバ関数へのポインタへのバインド: 100 6) メンバ関数へのポインタであるmem_fnへのバインド: 100 7) データメンバへのポインタへのバインド: 10 8) データメンバへのポインタであるmem_fnへのバインド: 10 9) スマートポインタを使用して参照先オブジェクトのメンバを呼び出し: 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)
|
メンバへのポインタから関数オブジェクトを作成する
(関数テンプレート) |