std:: bind_front, std:: bind_back
|
ヘッダーで定義
<functional>
|
||
std::bind_front
|
||
|
template
<
class
F,
class
...
Args
>
constexpr /* unspecified */ bind_front ( F && f, Args && ... args ) ; |
(1) | (C++20以降) |
|
template
<
auto
ConstFn,
class
...
Args
>
constexpr /* unspecified */ bind_front ( Args && ... args ) ; |
(2) | (C++26以降) |
std::bind_back
|
||
|
template
<
class
F,
class
...
Args
>
constexpr /* unspecified */ bind_back ( F && f, Args && ... args ) ; |
(3) | (C++23以降) |
|
template
<
auto
ConstFn,
class
...
Args
>
constexpr /* unspecified */ bind_back ( Args && ... args ) ; |
(4) | (C++26以降) |
関数テンプレート
std::bind_front
および
std::bind_back
は、呼び出し可能なターゲットをその
(1,2)
最初の、または
(3,4)
最後の
sizeof...
(
Args
)
個のパラメータを
args
に束縛して呼び出すことを可能にする完全転送呼び出しラッパーを生成します。
以下の条件が true でなければなりません。そうでない場合、プログラムは不適格となります:
- (1,3) std:: is_constructible_v < std:: decay_t < F > , F > ,
- (1,3) std:: is_move_constructible_v < std:: decay_t < F >> ,
-
(2,4)
decltypeがポインタまたはメンバポインタの場合、ConstFnはnullポインタではないこと、 - ( std:: is_constructible_v < std:: decay_t < Args > , Args > && ... ) ,
- ( std:: is_move_constructible_v < std:: decay_t < Args >> && ... ) .
目次 |
パラメータ
| f | - | Callable オブジェクト(関数オブジェクト、関数へのポインタ、関数への参照、メンバ関数へのポインタ、またはデータメンバへのポインタ)で、いくつかの引数に束縛されるもの |
| args | - | 呼び出し可能ターゲットの ( 1,2 ) 最初または ( 3,4 ) 最後の sizeof... ( Args ) 個のパラメータに束縛する引数のリスト |
| 型要件 | ||
-
std::
decay_t
<
F
>
は
MoveConstructible
の要件を満たさなければならない
|
||
-
std::
decay_t
<
Args
>
...
は
MoveConstructible
の要件を満たさなければならない
|
||
-
decltype
(
ConstFn
)
は
Callable
の要件を満たさなければならない
|
||
戻り値
関数オブジェクト(呼び出しラッパー)の型は
T
で、その詳細は規定されていない。ただし、同じ引数で
std::bind_front
または
std::bind_back
を2回呼び出した場合に返されるオブジェクトの型は同じである。
bind-partial
を
std::bind_front
または
std::bind_back
のいずれかとします。
返されたオブジェクトは以下のプロパティを持ちます:
bind-partial 戻り値型
メンバーオブジェクト
返されるオブジェクトは、以下のように保持しているかのように振る舞います:
tup
は
std::
tuple
<
std::
decay_t
<
Args
>
...
>
(
std::
forward
<
Args
>
(
args
)
...
)
で構築されるが、返されるオブジェクトの代入動作は未規定であり、名前は説明専用である。
コンストラクタ
bind-partial
の戻り値の型は、そのコピー/ムーブコンストラクタがメンバーごとのコピー/ムーブを実行するかのように振る舞います。これは、
CopyConstructible
すべてのメンバーオブジェクト(上記で指定)が
CopyConstructible
である場合に
MoveConstructible
であり、それ以外の場合は
です。
メンバー関数
operator()
以前の呼び出し
(
1,3
)
bind-partial
(f, args...)
または
(
2,4
)
bind-partial
<ConstFn>(args...)
から取得したオブジェクト
G
が与えられたとき、
G
を指すglvalue
g
が関数呼び出し式
g
(
call_args...
)
で呼び出されると、保存されたオブジェクトの呼び出しが以下のように行われます:
bind-partial
が
std::bind_front
の場合、
bind-partial
が
std::bind_front
の場合、
bind-partial
が
std::bind_back
である場合、
bind-partial
が
std::bind_back
の場合、
where
-
-
Nsは整数パック0, 1, ..., (sizeof...(Args) - 1)です。 -
gは、呼び出し式で左辺値の場合 std::invoke 式では左辺値となり、それ以外の場合は右辺値となります。したがって、 std :: move ( g ) ( call_args... ) は束縛された引数を呼び出しに移動できますが、 g ( call_args... ) はコピーします。
-
プログラムは、
g
がvolatile修飾型を持つ場合、不適格です。
メンバー関数 operator ( ) は、 noexcept が呼び出す std::invoke 式がnoexceptである場合にnoexceptとなります(言い換えれば、基盤となる呼び出し演算子の例外仕様を保持します)。
例外
注記
これらの関数テンプレートは
std::bind
を置き換えることを目的としています。
std::bind
とは異なり、任意の引数の再配置をサポートせず、ネストされたbind式や
std::reference_wrapper
に対する特別な扱いもありません。一方で、呼び出しラッパーオブジェクトの値カテゴリに注意を払い、基底となる呼び出し演算子の例外指定を伝播します。
std::invoke で説明されているように、非静的メンバ関数へのポインタまたは非静的データメンバへのポインタを呼び出す際には、第一引数はメンバがアクセスされるオブジェクトへの参照またはポインタ( std::shared_ptr や std::unique_ptr などのスマートポインタも含む)でなければなりません。
std::bind_front
または
std::bind_back
への引数は、コピーまたはムーブされ、
std::ref
または
std::cref
でラップされない限り、参照渡しされることはありません。
通常、関数またはメンバ関数への引数のバインディングには
(
1
)
std::bind_front
および
(
3
)
std::bind_back
を使用しますが、これには言語がポインタをデリファレンスする必要なく呼び出すべき関数を正確に知っているにもかかわらず、関数ポインタと引数を保存する必要があります。このような場合に「ゼロコスト」を保証するため、C++26では
(
2,4
)
バージョン(呼び出し可能オブジェクトを
定数テンプレートパラメータ
の引数として受け入れる)が導入されました。
| 機能テスト マクロ | 値 | 標準 | 機能 |
|---|---|---|---|
__cpp_lib_bind_front
|
201907L
|
(C++20) |
std::bind_front
,
(
1
)
|
202306L
|
(C++26) |
callableオブジェクトを定数テンプレート引数として
std::bind_front
に渡すことを許可,
(
2
)
|
|
__cpp_lib_bind_back
|
202202L
|
(C++23) |
std::bind_back
,
(
3
)
|
202306L
|
(C++26) |
callableオブジェクトを定数テンプレート引数として
std::bind_back
に渡すことを許可,
(
4
)
|
実装例
| (2) bind_front |
|---|
namespace detail { template<class T, class U> struct copy_const : std::conditional<std::is_const_v<T>, U const, U> {}; template<class T, class U, class X = typename copy_const<std::remove_reference_t<T>, U>::type> struct copy_value_category : std::conditional<std::is_lvalue_reference_v<T&&>, X&, X&&> {}; template <class T, class U> struct type_forward_like : copy_value_category<T, std::remove_reference_t<U>> {}; template <class T, class U> using type_forward_like_t = typename type_forward_like<T, U>::type; } template<auto ConstFn, class... Args> constexpr auto bind_front(Args&&... args) { using F = decltype(ConstFn); if constexpr (std::is_pointer_v<F> or std::is_member_pointer_v<F>) static_assert(ConstFn != nullptr); return [... bound_args(std::forward<Args>(args))]<class Self, class... T> ( this Self&&, T&&... call_args ) noexcept ( std::is_nothrow_invocable_v<F, detail::type_forward_like_t<Self, std::decay_t<Args>>..., T...> ) -> std::invoke_result_t<F, detail::type_forward_like_t<Self, std::decay_t<Args>>..., T...> { return std::invoke(ConstFn, std::forward_like<Self>(bound_args)..., std::forward<T>(call_args)...); }; } |
| (4) bind_back |
namespace detail { /* 上記と同じ */ } template<auto ConstFn, class... Args> constexpr auto bind_back(Args&&... args) { using F = decltype(ConstFn); if constexpr (std::is_pointer_v<F> or std::is_member_pointer_v<F>) static_assert(ConstFn != nullptr); return [... bound_args(std::forward<Args>(args))]<class Self, class... T> ( this Self&&, T&&... call_args ) noexcept ( std::is_nothrow_invocable_v<F, detail::type_forward_like_t<Self, T..., std::decay_t<Args>>...> ) -> std::invoke_result_t<F, detail::type_forward_like_t<Self, T..., std::decay_t<Args>>...> { return std::invoke(ConstFn, std::forward<T>(call_args)..., std::forward_like<Self>(bound_args)...); }; } |
例
#include <cassert> #include <functional> int minus(int a, int b) { return a - b; } struct S { int val; int minus(int arg) const noexcept { return val - arg; } }; int main() { auto fifty_minus = std::bind_front(minus, 50); assert(fifty_minus(3) == 47); // 次と等価: minus(50, 3) == 47 auto member_minus = std::bind_front(&S::minus, S{50}); assert(member_minus(3) == 47); //: S tmp{50}; tmp.minus(3) == 47 // noexcept指定は保持される: static_assert(!noexcept(fifty_minus(3))); static_assert(noexcept(member_minus(3))); // ラムダのバインド: auto plus = [](int a, int b) { return a + b; }; auto forty_plus = std::bind_front(plus, 40); assert(forty_plus(7) == 47); // 次と等価: plus(40, 7) == 47 #if __cpp_lib_bind_front >= 202306L auto fifty_minus_cpp26 = std::bind_front<minus>(50); assert(fifty_minus_cpp26(3) == 47); auto member_minus_cpp26 = std::bind_front<&S::minus>(S{50}); assert(member_minus_cpp26(3) == 47); auto forty_plus_cpp26 = std::bind_front<plus>(40); assert(forty_plus(7) == 47); #endif #if __cpp_lib_bind_back >= 202202L auto madd = [](int a, int b, int c) { return a * b + c; }; auto mul_plus_seven = std::bind_back(madd, 7); assert(mul_plus_seven(4, 10) == 47); //: madd(4, 10, 7) == 47 #endif #if __cpp_lib_bind_back >= 202306L auto mul_plus_seven_cpp26 = std::bind_back<madd>(7); assert(mul_plus_seven_cpp26(4, 10) == 47); #endif }
参考文献
- C++26標準 (ISO/IEC 14882:2026):
-
- TBD 関数テンプレート bind_front および bind_back [func.bind.partial]
- C++23標準 (ISO/IEC 14882:2024):
-
- 22.10.14 関数テンプレート bind_front および bind_back [func.bind.partial]
- C++20規格 (ISO/IEC 14882:2020):
-
- 20.14.14 関数テンプレート bind_front [func.bind.front]
関連項目
|
(C++11)
|
1つ以上の引数を関数オブジェクトにバインドする
(関数テンプレート) |
|
(C++11)
|
メンバへのポインタから関数オブジェクトを作成する
(関数テンプレート) |