- functional[meta header]
- std[meta namespace]
- function template[meta id-type]
- cpp23[meta cpp]
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
}
- unspecified[italic]
関数の引数を末尾から順に部分適用する。
先頭から適用する場合は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_poinetr_v
<F> ||
is_member_poinetr_v
<F>
がtrue
ならば、f != nullptr
であること
呼び出し可能なf
をstd::invoke()
で呼び出した時に必要な引数列に後方一致するf
とargs...
を完全転送して保持し、後から残りの引数リストを渡すことでf
を呼び出せる未規定の関数オブジェクトを返す。
返される関数オブジェクトは渡された引数(f, args...
)を参照として保持せず、適切にコピー/ムーブして保持する。
- (1) : 関数オブジェクト
f
のムーブによって任意の例外が送出される可能性がある - (2) :
bound_args
の初期化による任意の例外が送出される可能性がある
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; }));
}
- std::bind_back[color ff0000]
- std::ranges::range_adaptor_closure[link /reference/ranges/range_adaptor_closure.md]
- std::bind_back[link /reference/functional/bind_back.md]
- std::invocable[link /reference/concepts/invocable.md]
- std::views::all[link /reference/ranges/all.md]
- std::ranges::range[link /reference/ranges/range.md]
- std::ranges::viewable_range[link /reference/ranges/viewable_range.md]
- std::ranges::join_view[link /reference/ranges/join_view.md]
- std::ranges::transform_view[link /reference/ranges/transform_view.md]
[0, 1, 4, 9, 16, 25, 36]
- C++23
- Clang: ??
- GCC: ??
- ICC: ??
- Visual C++: ??