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.
f.std::invoke(f, bound_args..., call_args...).std::invoke(ConstFn, bound_args..., call_args...).std::invoke(f, call_args..., bound_args...).std::invoke(ConstFn, call_args..., bound_args...).Следующие условия должны быть true, в противном случае программа некорректна:
-
(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. |
||
Возвращаемое значение
Функциональный объект (обёртка вызова) неопределённого типа T, за исключением того, что типы объектов, возвращаемых двумя вызовами std::bind_front или std::bind_back с одинаковыми аргументами, совпадают.
Пусть bind-partial обозначает либо std::bind_front, либо std::bind_back.
Возвращаемый объект обладает следующими свойствами:
тип возвращаемого значения bind-partial
Объекты-члены
Возвращаемый объект ведёт себя так, как если бы он хранил:
fd типа std::decay_t<F>, напрямую инициализируемый не списком из std::forward<F>(f), иstd::tuple tup, созданный с помощью std::tuple<std::decay_t<Args>...>(std::forward<Args>(args)...), за исключением того, что поведение возвращаемого объекта при присваивании не определено, а имена приведены только для описания.Конструкторы
Возвращаемый тип bind-partial ведёт себя так, как если бы его конструкторы копирования/перемещения выполняли поэлементное копирование/перемещение. Он является CopyConstructible, если все его объекты-члены (указанные выше) являются CopyConstructible, и в противном случае является MoveConstructible.
Функция-член operator()
Для объекта G, полученного в результате более раннего вызова (1,3) bind-partial(f, args...) или (2,4) bind-partial<ConstFn>(args...), если glvalue g, обозначающая G, вызывается в выражении вызова функции g(call_args...), выполняется вызов сохранённого объекта, как если бы он был выполнен следующим образом:
std::invoke(g.fd, std::get<Ns>(g.tup)..., call_args...), когда bind-partial является std::bind_front,std::invoke(ConstFn, std::get<Ns>(g.tup)..., call_args...), когда bind-partial является std::bind_front,std::invoke(g.fd, call_args..., std::get<Ns>(g.tup)...), когда bind-partial является std::bind_back,std::invoke(ConstFn, call_args..., std::get<Ns>(g.tup)...), когда bind-partial является std::bind_back,где
-
Ns— целочисленный набор0, 1, ..., (sizeof...(Args) - 1), -
gявляется lvalue в выраженииstd::invoke, если оно является lvalue в выражении вызова, и rvalue в противном случае. Таким образом,std::move(g)(call_args...)может переместить привязанные аргументы в вызов, тогда какg(call_args...)скопирует их.
Программа некорректна, если g имеет тип с квалификатором volatile.
Член operator() является noexcept, если вызываемое им выражение std::invoke является noexcept (иначе говоря, он сохраняет спецификацию исключений базового оператора вызова).
Исключения
Примечания
Эти функциональные шаблоны предназначены для замены std::bind. В отличие от std::bind, они не поддерживают произвольную перестановку аргументов и не обрабатывают особым образом вложенные 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<typename To, typename From>
using forward_like_t = decltype(std::forward_like<From>(std::declval<To>()));
}
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::forward_like_t<std::decay_t<Args>, Self>...,
T...
>
)
-> std::invoke_result_t<F,
detail::forward_like_t<std::decay_t<Args>, Self>...,
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,
T...,
detail::forward_like_t<std::decay_t<Args>, Self>...
>
)
-> std::invoke_result_t<F,
T...,
detail::forward_like_t<std::decay_t<Args>, Self>...
>
{
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 (ISO/IEC 14882:2020):
- 20.14.14 Функциональный шаблон bind_front [func.bind.front]
См. также
|
(C++11) | привязывает один или несколько аргументов к функциональному объекту (функциональный шаблон) |
|
(C++11) | создаёт функциональный объект из указателя на член (функциональный шаблон) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/utility/functional/bind_front