最終更新日時(UTC):
が更新

履歴 編集

function template
<functional>

std::bind_back(C++23)

namespace std {
  template <class F, class... Args>
  constexpr unspecified bind_back(F&&, Args&&...);
}

概要

関数の引数を末尾から順に部分適用する。

先頭から適用する場合はbind_frontを用いる。

テンプレートパラメータ制約

decay_t<F>を適用した型をFDstd::decay_t<Args>...を適用した型パラメータパックをBoundArgsであるとして、

適格要件

戻り値

呼び出し可能なfstd::invoke()で呼び出した時に必要な引数列に後方一致するfargs...を完全転送して保持し、後から残りの引数リストを渡すことでfを呼び出せる未規定の関数オブジェクトを返す。

返される関数オブジェクトは渡された引数(f, args...)を参照として保持せず、適切にコピー/ムーブして保持する。

例外

  • 関数オブジェクトfのムーブによって任意の例外が送出される可能性がある

この機能が必要になった背景・経緯

C++23でRangeアダプタユーザー定義がサポートされた。

Rangeアダプタオブジェクトであるadaptorが2つ以上の引数をとる場合、以下の3つの式は等しい。

adaptor(range, args...)
adaptor(args...)(range)
range | adaptor(args...)

ここで、Rangeアダプタオブジェクトの第2引数以降を部分適用した結果がRangeアダプタクロージャオブジェクトとなる。 ユーザー定義するRangeアダプタオブジェクトのoperator()において、この部分適用を行うためのユーティリティとしてbind_backが提案された。

#include <ranges>
#include <vector>
#include <functional>
#include <print>

template <typename F>
class closure_t : public std::ranges::range_adaptor_closure<closure_t<F>> {
  F f;
public:
  constexpr closure_t(F f) : f(f) { }

  template <std::ranges::range R>
  requires std::invocable<F const&, R>
  constexpr auto operator()(R&& r) const {
    return f(std::views::all(std::forward<R>(r)));
  }
};

template <typename F>
class adaptor_t {
  F f;
public:
  constexpr adaptor_t(F f) : f(f) { }

  template <typename... Args>
  constexpr auto operator()(Args&&... args) const {
    if constexpr (std::invocable<F const&, Args...>) {
      return f(std::forward<Args>(args)...);
    } else {
      return closure_t(std::bind_back(f, std::forward<Args>(args)...));
    }
  }
};

inline constexpr closure_t user_defined_join
  = []<std::ranges::viewable_range R>
    (R&& r) {
      return std::ranges::join_view(std::forward<R>(r));
    };

inline constexpr adaptor_t user_defined_transform
  = []<std::ranges::viewable_range R, typename F>
    (R&& r, F&& f) {
      return std::ranges::transform_view(std::forward<R>(r), std::forward<F>(f));
    };

int main() {
  std::vector<std::vector<int>> vv = {{0, 1, 2}, {3, 4, 5}, {6}};

  std::println("{}", vv | user_defined_join | user_defined_transform([](int x){ return x * x; }));
}

出力

[0, 1, 4, 9, 16, 25, 36]

バージョン

言語

  • C++23

処理系

参照