std:: bind_front, std:: bind_back
|
Definido en el encabezado
<functional>
|
||
std::bind_front
|
||
|
template
<
class
F,
class
...
Args
>
constexpr /* no especificado */ bind_front ( F && f, Args && ... args ) ; |
(1) | (desde C++20) |
|
template
<
auto
ConstFn,
class
...
Args
>
constexpr /* no especificado */ bind_front ( Args && ... args ) ; |
(2) | (desde C++26) |
std::bind_back
|
||
|
template
<
class
F,
class
...
Args
>
constexpr /* no especificado */ bind_back ( F && f, Args && ... args ) ; |
(3) | (desde C++23) |
|
template
<
auto
ConstFn,
class
...
Args
>
constexpr /* no especificado */ bind_back ( Args && ... args ) ; |
(4) | (desde C++26) |
Las plantillas de función
std::bind_front
y
std::bind_back
generan un envoltorio de llamada de reenvío perfecto que permite invocar el objetivo invocable con sus
(1,2)
primeros o
(3,4)
últimos
sizeof...
(
Args
)
parámetros vinculados a
args
.
Las siguientes condiciones deben ser true , de lo contrario el programa está mal formado:
- (1,3) std:: is_constructible_v < std:: decay_t < F > , F > ,
- (1,3) std:: is_move_constructible_v < std:: decay_t < F >> ,
-
(2,4)
Si
decltype
(
ConstFn
)
es un puntero o un puntero-a-miembro entonces
ConstFnno es un puntero nulo, - ( std:: is_constructible_v < std:: decay_t < Args > , Args > && ... ) ,
- ( std:: is_move_constructible_v < std:: decay_t < Args >> && ... ) .
Contenidos |
Parámetros
| f | - | Callable objeto (objeto función, puntero a función, referencia a función, puntero a función miembro, o puntero a miembro de datos) que será vinculado a algunos argumentos |
| args | - | lista de los argumentos a vincular a los ( 1,2 ) primeros o ( 3,4 ) últimos sizeof... ( Args ) parámetros del objetivo invocable |
| Requisitos de tipo | ||
-
std::
decay_t
<
F
>
debe cumplir con los requisitos de
MoveConstructible
.
|
||
-
std::
decay_t
<
Args
>
...
debe cumplir con los requisitos de
MoveConstructible
.
|
||
-
decltype
(
ConstFn
)
debe cumplir con los requisitos de
Callable
.
|
||
Valor de retorno
Un objeto función (el envoltorio de llamada) de tipo
T
que no está especificado, excepto que los tipos de objetos devueltos por dos llamadas a
std::bind_front
o
std::bind_back
con los mismos argumentos son los mismos.
Sea
bind-partial
ya sea
std::bind_front
o
std::bind_back
.
El objeto devuelto tiene las siguientes propiedades:
bind-partial tipo de retorno
Objetos miembro
El objeto devuelto se comporta como si contuviera:
fd
de tipo
std::
decay_t
<
F
>
inicializado por non-lista directa desde
std::
forward
<
F
>
(
f
)
, y
tup
construido con
std::
tuple
<
std::
decay_t
<
Args
>
...
>
(
std::
forward
<
Args
>
(
args
)
...
)
, excepto que el comportamiento de asignación del objeto devuelto no está especificado y los nombres son solo para exposición.
Constructores
El tipo de retorno de
bind-partial
se comporta como si sus constructores de copia/movimiento realizaran una copia/movimiento miembro a miembro. Es
CopyConstructible
si todos sus objetos miembro (especificados anteriormente) son
CopyConstructible
, y es
MoveConstructible
en caso contrario.
Función miembro
operator()
Dado un objeto
G
obtenido de una llamada anterior a
(
1,3
)
bind-partial
(f, args...)
o
(
2,4
)
bind-partial
<ConstFn>(args...)
, cuando un glvalue
g
que designa
G
es invocado en una expresión de llamada a función
g
(
call_args...
)
, tiene lugar una invocación del objeto almacenado, como si fuera mediante:
bind-partial
es
std::bind_front
,
bind-partial
es
std::bind_front
,
bind-partial
es
std::bind_back
,
bind-partial
es
std::bind_back
,
donde
-
-
Nses un paquete de enteros0, 1, ..., (sizeof...(Args) - 1), -
ges un lvalue en la expresión std::invoke si es un lvalue en la expresión de llamada, y es un rvalue en caso contrario. Por lo tanto std :: move ( g ) ( call_args... ) puede mover los argumentos vinculados a la llamada, mientras que g ( call_args... ) copiaría.
-
El programa está mal formado si
g
tiene tipo calificado como volatile.
El miembro operator ( ) es noexcept si la expresión std::invoke que llama es noexcept (en otras palabras, preserva la especificación de excepciones del operador de llamada subyacente).
Excepciones
Notas
Estas plantillas de función están destinadas a reemplazar
std::bind
. A diferencia de
std::bind
, no admiten reordenamiento arbitrario de argumentos y no tienen tratamiento especial para expresiones de enlace anidadas o
std::reference_wrapper
s. Por otro lado, prestan atención a la categoría de valor del objeto contenedor de llamada y propagan la especificación de excepciones del operador de llamada subyacente.
Como se describe en std::invoke , al invocar un puntero a función miembro no estática o puntero a dato miembro no estático, el primer argumento debe ser una referencia o puntero (incluyendo, posiblemente, punteros inteligentes como std::shared_ptr y std::unique_ptr ) a un objeto cuyo miembro será accedido.
Los argumentos de
std::bind_front
o
std::bind_back
se copian o mueven, y nunca se pasan por referencia a menos que se envuelvan en
std::ref
o
std::cref
.
Normalmente, enlazar argumentos a una función o a una función miembro usando
(
1
)
std::bind_front
y
(
3
)
std::bind_back
requiere almacenar un puntero a función junto con los argumentos, aunque el lenguaje sabe exactamente qué función llamar sin necesidad de desreferenciar el puntero. Para garantizar "costo cero" en esos casos, C++26 introduce las versiones
(
2,4
)
(que aceptan el objeto invocable como argumento para
parámetro de plantilla constante
).
| Macro de prueba de características | Valor | Std | Característica |
|---|---|---|---|
__cpp_lib_bind_front
|
201907L
|
(C++20) |
std::bind_front
,
(
1
)
|
202306L
|
(C++26) |
Permitir pasar objetos invocables como argumentos de plantilla constantes a
std::bind_front
,
(
2
)
|
|
__cpp_lib_bind_back
|
202202L
|
(C++23) |
std::bind_back
,
(
3
)
|
202306L
|
(C++26) |
Permitir pasar objetos invocables como argumentos de plantilla constantes a
std::bind_back
,
(
4
)
|
Implementación posible
| (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 { /* es lo mismo que arriba */ } 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)...); }; } |
Ejemplo
#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); // equivalente a: 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 // La especificación noexcept se conserva: static_assert(!noexcept(fifty_minus(3))); static_assert(noexcept(member_minus(3))); // Enlace de una lambda: auto plus = [](int a, int b) { return a + b; }; auto forty_plus = std::bind_front(plus, 40); assert(forty_plus(7) == 47); // equivalente a: 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 }
Referencias
- Estándar C++26 (ISO/IEC 14882:2026):
-
- TBD Plantillas de función bind_front y bind_back [func.bind.partial]
- Estándar C++23 (ISO/IEC 14882:2024):
-
- 22.10.14 Plantillas de función bind_front y bind_back [func.bind.partial]
- Estándar C++20 (ISO/IEC 14882:2020):
-
- 20.14.14 Plantilla de función bind_front [func.bind.front]
Véase también
|
(C++11)
|
vincula uno o más argumentos a un objeto función
(plantilla de función) |
|
(C++11)
|
crea un objeto función a partir de un puntero a miembro
(plantilla de función) |