namespace std {
template <class F, class... Args>
constexpr unspecified bind_back(F&& f, Args&&... args); // (1) C++23
template <auto f, class... Args>
constexpr unspecified bind_back(Args&&... args); // (2) C++26
}
概要
関数の引数を末尾から順に部分適用する。
先頭から適用する場合はbind_frontを用いる。
事前条件
decay_t<F>を適用した型をFD、decay_t<Args>...を適用した型パラメータパックをBoundArgsとして
- (1) :
FDがCpp17MoveConstructible要件を満たすことBoundArgsのそれぞれの型Tiがオブジェクト型である場合、Cpp17MoveConstructible要件を満たすこと
- (2) :
BoundArgsのそれぞれの型TiがCpp17MoveConstructible要件を満たすこと
適格要件
- (1) :
is_constructible_v<FD, F> && is_move_constructible_v<FD> && (is_constructible_v<BoundArgs, Args> && ...) && (is_move_constructible_v<BoundArgs> && ...)がtrueであること
- (2) :
Fをfの型として(is_constructible_v<BoundArgs, Args> && ...)がtrue、かつ(is_move_constructible_v<BoundArgs> && ...)がtrue、かつ- もし
is_pointer_v<F> || is_member_pointer_v<F>がtrueならば、f != nullptrであること
戻り値
呼び出し可能なfをstd::invoke()で呼び出した時に必要な引数列に後方一致するfとargs...を完全転送して保持し、後から残りの引数リストを渡すことでfを呼び出せる未規定の関数オブジェクトを返す。
返される関数オブジェクトは渡された引数(f, args...)を参照として保持せず、適切にコピー/ムーブして保持する。
例外
この機能が必要になった背景・経緯
C++23でRangeアダプタのユーザー定義がサポートされた。
Rangeアダプタオブジェクトであるadaptorが2つ以上の引数をとる場合、以下の3つの式は等しい。
ここで、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
処理系
- Clang: ??
- GCC: ??
- ICC: ??
- Visual C++: ??