std::bind_front, std::bind_back
Определено в заголовке <functional> | ||
|---|---|---|
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) |
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::bind_front(f, bound_args...)(call_args...) эквивалентноstd::invoke(f, bound_args..., call_args...). std::bind_front<ConstFn>(bound_args...)(call_args...) эквивалентноstd::invoke(ConstFn, bound_args..., call_args...). std::bind_back(f, bound_args...)(call_args...) эквивалентноstd::invoke(f, call_args..., bound_args...). std::bind_back<ConstFn>(bound_args...)(call_args...) эквивалентноstd::invoke(ConstFn, call_args..., bound_args...). Следующие условия должны быть истинными, в противном случае программа является некорректной:
- (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 | - | Объект Callable (объект-функция, указатель на функцию, ссылка на функцию, указатель на функцию-член, или указатель на член данных), который будет привязан к некоторым аргументам |
| 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-части
Члены-объекты
Возвращаемый объект ведет себя так, как если бы он содержал:
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...), когда левореферентный 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— это целое число pack0, 1, ..., (sizeof...(Args) - 1), -
g— это левореферентное значение в выраженииstd::invoke, если это левореферентное значение в выражении вызова, и это правореферентное значение в противном случае. Таким образом,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) (которые принимают вызываемый объект как аргумент для параметра шаблона нетипа).
| Макрос проверки возможностей | Значение | Std | Функция |
|---|---|---|---|
__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<class T, class U>
struct copy_const
: std::conditional<std::is_const_v<T>, U const, U> {};
template<class T, class U,
class X = typename copy_const<std::remove_reference_t<T>, U>::type>
struct copy_value_category
: std::conditional<std::is_lvalue_reference_v<T&&>, X&, X&&> {};
template <class T, class U>
struct type_forward_like
: copy_value_category<T, std::remove_reference_t<U>> {};
template <class T, class U>
using type_forward_like_t = typename type_forward_like<T, U>::type;
}
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::type_forward_like_t<Self, std::decay_t<Args>>..., T...>
)
-> std::invoke_result_t<F,
detail::type_forward_like_t<Self, std::decay_t<Args>>..., 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,
detail::type_forward_like_t<Self, T..., std::decay_t<Args>>...>
)
-> std::invoke_result_t<F,
detail::type_forward_like_t<Self, T..., std::decay_t<Args>>...>
{
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):
- Функции-шаблоны bind_front и bind_back [func.bind.partial] (TBD)
- Стандарт C++23 (ISO/IEC 14882:2023):
- 22.10.14 Функции-шаблоны bind_front и bind_back [func.bind.partial]
- Стандарт C++20 (ISO/IEC 14882:2020):
- Шаблон функции 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/w/cpp/utility/functional/bind_front