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 でなければならず、そうでなければプログラムはill-formedになります。
- (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) がポインタまたはメンバーへのポインタである場合、
ConstFnはヌルポインタではない, - (std::is_constructible_v<std::decay_t<Args>, Args> && ...),
- (std::is_move_constructible_v<std::decay_t<Args>> && ...).
目次 |
[編集] パラメータ
| f | - | 一部の引数にバインドされる 呼び出し可能 オブジェクト (関数オブジェクト、関数へのポインタ、関数への参照、メンバ関数へのポインタ、またはデータメンバへのポインタ) |
| args | - | 呼び出し可能ターゲットの (1,2) 最初の、または (3,4) 最後の sizeof...(Args) パラメータにバインドする引数のリスト |
| 型要件 | ||
-std::decay_t<F> は MoveConstructible の要件を満たさなければなりません。 | ||
-std::decay_t<Args>... は MoveConstructible の要件を満たさなければなりません。 | ||
-decltype(ConstFn) は Callable の要件を満たさなければなりません。 | ||
[編集] 戻り値
2つの std::bind_front または std::bind_back 呼び出しが同じ引数で返されるオブジェクトの型が同じであること以外は、不定な型 T の関数オブジェクト(呼び出しラッパー)。
bind-partial を std::bind_front または std::bind_back とします。
返されるオブジェクトは以下のプロパティを持ちます。
bind-partial の戻り値の型
メンバーオブジェクト
返されるオブジェクトは、次のように保持されているかのように振る舞います。
tup を保持します。ただし、返されるオブジェクトの代入動作は未規定であり、名前は説明目的のみです。コンストラクタ
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...) で呼び出されると、次のように格納されたオブジェクトの呼び出しが行われます。
ここで、
-
Nsは整数パック0, 1, ..., (sizeof...(Args) - 1)です。 -
gは、呼び出し式で lvalue であれば std::invoke 式では lvalue であり、そうでなければ rvalue です。したがって、std::move(g)(call_args...) はバインドされた引数を呼び出しにムーブできますが、g(call_args...) はコピーします。
-
g が揮発性修飾型を持つ場合、プログラムは ill-formed です。
メンバーの operator() は、それが呼び出す std::invoke 式が noexcept であれば noexcept です(つまり、基となる呼び出し演算子の例外指定を保持します)。
[編集] 例外
[編集] 注釈
これらの関数テンプレートは std::bind を置き換えることを目的としています。std::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) | 呼び出し可能オブジェクトを std::bind_front, (2) への非型テンプレート引数として渡すことを許可する | |
__cpp_lib_bind_back |
202202L |
(C++23) | std::bind_back, (3) |
202306L |
(C++26) | 呼び出し可能オブジェクトを 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 { /* is the same as above */ } 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); // equivalent to: 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-specification is preserved: static_assert(!noexcept(fifty_minus(3))); static_assert(noexcept(member_minus(3))); // Binding of a lambda: auto plus = [](int a, int b) { return a + b; }; auto forty_plus = std::bind_front(plus, 40); assert(forty_plus(7) == 47); // equivalent to: 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 standard (ISO/IEC 14882:2020)
- 20.14.14 関数テンプレート bind_front [func.bind.front]
[編集] 関連項目
| (C++11) |
1つ以上の引数を関数オブジェクトに束縛する (関数テンプレート) |
| (C++11) |
メンバへのポインタから関数オブジェクトを生成する (関数テンプレート) |