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
.
Следующие условия должны быть 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 | - | 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-partial тип возвращаемого значения
Объекты-члены
Возвращаемый объект ведет себя так, как будто он содержит:
fd
типа
std::
decay_t
<
F
>
прямое не-списковое инициализирование из
std::
forward
<
F
>
(
f
)
, и
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...
)
, происходит вызов сохраненного объекта, как если бы с помощью:
bind-partial
является
std::bind_front
,
bind-partial
является
std::bind_front
,
bind-partial
является
std::bind_back
,
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<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 { /* то же самое, что и выше */ } 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); // эквивалентно: 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 сохраняется: static_assert(!noexcept(fifty_minus(3))); static_assert(noexcept(member_minus(3))); // Привязка лямбда-выражения: auto plus = [](int a, int b) { return a + b; }; auto forty_plus = std::bind_front(plus, 40); assert(forty_plus(7) == 47); // эквивалентно: 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)
|
создает функциональный объект из указателя на член
(шаблон функции) |