|
| 1 | +# bind_back |
| 2 | +* functional[meta header] |
| 3 | +* std[meta namespace] |
| 4 | +* function template[meta id-type] |
| 5 | +* cpp23[meta cpp] |
| 6 | + |
| 7 | +```cpp |
| 8 | +namespace std { |
| 9 | + template <class F, class... Args> |
| 10 | + constexpr unspecified bind_back(F&&, Args&&...); |
| 11 | +} |
| 12 | +``` |
| 13 | +* unspecified[italic] |
| 14 | +
|
| 15 | +## 概要 |
| 16 | +関数の引数を末尾から順に部分適用する。 |
| 17 | +
|
| 18 | +先頭から適用する場合は[`bind_front`](bind_front.md)を用いる。 |
| 19 | +
|
| 20 | +## テンプレートパラメータ制約 |
| 21 | +[`decay_t`](/reference/type_traits/decay.md)`<F>`を適用した型を`FD`、 |
| 22 | +[`std::decay_t`](/reference/type_traits/decay.md)`<Args>...`を適用した型パラメータパックを`BoundArgs`であるとして、 |
| 23 | +
|
| 24 | +- `FD`が[`std::move_constructible`](/reference/concepts/move_constructible.md)要件を満たすこと |
| 25 | +- `BoundArgs`のそれぞれの型`Ti`が[オブジェクト型](/reference/type_traits/is_object.md)である場合、[`std::move_constructible`](/reference/concepts/move_constructible.md)要件を満たすこと |
| 26 | +
|
| 27 | +
|
| 28 | +## 適格要件 |
| 29 | +- [`conjunction_v`](/reference/type_traits/conjunction.md)`<`[`is_constructible`](/reference/type_traits/is_constructible.md)`<FD, F>,` [`is_move_constructible`](/reference/type_traits/is_move_constructible.md)`<FD>,` [`is_constructible`](/reference/type_traits/is_constructible.md)`<BoundArgs, Args>...,` [`is_move_constructible`](/reference/type_traits/is_move_constructible.md)`<BoundArgs>...>`が`true`であること |
| 30 | +
|
| 31 | +
|
| 32 | +## 戻り値 |
| 33 | +
|
| 34 | +呼び出し可能な`f`を[`std::invoke()`](invoke.md)で呼び出した時に必要な引数列に後方一致する`f`と`args...`を完全転送して保持し、後から残りの引数リストを渡すことで`f`を呼び出せる未規定の関数オブジェクトを返す。 |
| 35 | +
|
| 36 | +返される関数オブジェクトは渡された引数(`f, args...`)を参照として保持せず、適切にコピー/ムーブして保持する。 |
| 37 | +
|
| 38 | +## 例外 |
| 39 | +- 関数オブジェクト`f`のムーブによって任意の例外が送出される可能性がある |
| 40 | +
|
| 41 | +## この機能が必要になった背景・経緯 |
| 42 | +
|
| 43 | +C++23で[`Rangeアダプタ`](/reference/ranges/range.md)のユーザー定義がサポートされた。 |
| 44 | +
|
| 45 | +[`Rangeアダプタオブジェクト`](/reference/ranges/range.md)である`adaptor`が2つ以上の引数をとる場合、以下の3つの式は等しい。 |
| 46 | +
|
| 47 | +```cpp |
| 48 | +adaptor(range, args...) |
| 49 | +adaptor(args...)(range) |
| 50 | +range | adaptor(args...) |
| 51 | +``` |
| 52 | + |
| 53 | +ここで、Rangeアダプタオブジェクトの第2引数以降を部分適用した結果が[`Rangeアダプタクロージャオブジェクト`](/reference/ranges/range.md)となる。 |
| 54 | +ユーザー定義するRangeアダプタオブジェクトの`operator()`において、この部分適用を行うためのユーティリティとして`bind_back`が提案された。 |
| 55 | + |
| 56 | +## 例 |
| 57 | +```cpp example |
| 58 | +#include <ranges> |
| 59 | +#include <vector> |
| 60 | +#include <functional> |
| 61 | +#include <print> |
| 62 | + |
| 63 | +template <typename F> |
| 64 | +class closure_t : public std::ranges::range_adaptor_closure<closure_t<F>> { |
| 65 | + F f; |
| 66 | +public: |
| 67 | + constexpr closure_t(F f) : f(f) { } |
| 68 | + |
| 69 | + template <std::ranges::range R> |
| 70 | + requires std::invocable<F const&, R> |
| 71 | + constexpr auto operator()(R&& r) const { |
| 72 | + return f(std::views::all(std::forward<R>(r))); |
| 73 | + } |
| 74 | +}; |
| 75 | + |
| 76 | +template <typename F> |
| 77 | +class adaptor_t { |
| 78 | + F f; |
| 79 | +public: |
| 80 | + constexpr adaptor_t(F f) : f(f) { } |
| 81 | + |
| 82 | + template <typename... Args> |
| 83 | + constexpr auto operator()(Args&&... args) const { |
| 84 | + if constexpr (std::invocable<F const&, Args...>) { |
| 85 | + return f(std::forward<Args>(args)...); |
| 86 | + } else { |
| 87 | + return closure_t(std::bind_back(f, std::forward<Args>(args)...)); |
| 88 | + } |
| 89 | + } |
| 90 | +}; |
| 91 | + |
| 92 | +inline constexpr closure_t user_defined_join |
| 93 | + = []<std::ranges::viewable_range R> |
| 94 | + (R&& r) { |
| 95 | + return std::ranges::join_view(std::forward<R>(r)); |
| 96 | + }; |
| 97 | + |
| 98 | +inline constexpr adaptor_t user_defined_transform |
| 99 | + = []<std::ranges::viewable_range R, typename F> |
| 100 | + (R&& r, F&& f) { |
| 101 | + return std::ranges::transform_view(std::forward<R>(r), std::forward<F>(f)); |
| 102 | + }; |
| 103 | + |
| 104 | +int main() { |
| 105 | + std::vector<std::vector<int>> vv = {{0, 1, 2}, {3, 4, 5}, {6}}; |
| 106 | + |
| 107 | + std::println("{}", vv | user_defined_join | user_defined_transform([](int x){ return x * x; })); |
| 108 | +} |
| 109 | +``` |
| 110 | +* std::bind_back[color ff0000] |
| 111 | +* std::ranges::range_adaptor_closure[link /reference/ranges/range_adaptor_closure.md] |
| 112 | +* std::bind_back[link /reference/functional/bind_back.md] |
| 113 | +* std::invocable[link /reference/concepts/invocable.md] |
| 114 | +* std::views::all[link /reference/ranges/all.md] |
| 115 | +* std::ranges::range[link /reference/ranges/range.md] |
| 116 | +* std::ranges::viewable_range[link /reference/ranges/viewable_range.md] |
| 117 | +* std::ranges::join_view[link /reference/ranges/join_view.md] |
| 118 | +* std::ranges::transform_view[link /reference/ranges/transform_view.md] |
| 119 | +
|
| 120 | +### 出力 |
| 121 | +``` |
| 122 | +[0, 1, 4, 9, 16, 25, 36] |
| 123 | +``` |
| 124 | + |
| 125 | +## バージョン |
| 126 | +### 言語 |
| 127 | +- C++23 |
| 128 | + |
| 129 | +### 処理系 |
| 130 | +- [Clang](/implementation.md#clang): ?? |
| 131 | +- [GCC](/implementation.md#gcc): ?? |
| 132 | +- [ICC](/implementation.md#icc): ?? |
| 133 | +- [Visual C++](/implementation.md#visual_cpp): ?? |
| 134 | + |
| 135 | +## 参照 |
| 136 | +- [P2387R3 Pipe support for user-defined range adaptors](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2387r3.html#nanorange) |
| 137 | +- [rangesのパイプにアダプトするには](https://onihusube.hatenablog.com/entry/2022/04/24/010041) |
0 commit comments