std:: bind
|
Definido en el encabezado
<functional>
|
||
|
template
<
class
F,
class
...
Args
>
/* unspecified */ bind ( F && f, Args && ... args ) ; |
(1) |
(desde C++11)
(constexpr desde C++20) |
|
template
<
class
R,
class
F,
class
...
Args
>
/* unspecified */ bind ( F && f, Args && ... args ) ; |
(2) |
(desde C++11)
(constexpr desde C++20) |
La plantilla de función
std::bind
genera un wrapper de llamada de reenvío para
f
. Llamar a este wrapper es equivalente a invocar
f
con algunos de sus argumentos
vinculados
a
args
.
Si
std::
is_constructible
<
std::
decay
<
F
>
::
type
, F
>
::
value
es
false
, o
std::
is_constructible
<
std::
decay
<
Arg_i
>
::
type
, Arg_i
>
::
value
es
false
para cualquier tipo
Arg_i
en
Args
, el programa está mal formado.
Si
std::
decay
<
Ti
>
::
type
o cualquier tipo en
Args
no es
MoveConstructible
o
Destructible
, el comportamiento es indefinido.
Contenidos |
Parámetros
| f | - | Callable objeto invocable (objeto función, puntero a función, referencia a función, puntero a función miembro, o puntero a dato miembro) que será vinculado a algunos argumentos |
| args | - |
lista de argumentos a vincular, con los argumentos no vinculados reemplazados por los
placeholders
_1
,
_2
,
_3
... del espacio de nombres
std::placeholders
|
Valor de retorno
Un objeto función
g
de tipo no especificado
T
, para el cual
std::
is_bind_expression
<
T
>
::
value
es
true
. Tiene los siguientes miembros:
std::bind tipo de retorno
Objetos miembro
El tipo de retorno de
std::bind
contiene un objeto miembro de tipo
std::
decay
<
F
>
::
type
construido a partir de
std::
forward
<
F
>
(
f
)
, y un objeto por cada uno de
args...
, de tipo
std::
decay
<
Arg_i
>
::
type
, similarmente construido a partir de
std::
forward
<
Arg_i
>
(
arg_i
)
.
Constructores
El tipo de retorno de
std::bind
es
CopyConstructible
si todos sus objetos miembro (especificados anteriormente) son CopyConstructible, y es
MoveConstructible
en caso contrario. El tipo define los siguientes miembros:
Tipo miembro
|
(hasta C++20) |
Función miembro
operator()
Cuando g es invocado en una expresión de llamada a función g ( u1, u2, ... uM ) , tiene lugar una invocación del objeto almacenado, como si fuera mediante
INVOKE
(
fd,
std::
forward
<
V1
>
(
v1
)
,
std::
forward
<
V2
>
(
v2
)
, ...,
std::
forward
<
VN
>
(
vN
)
)
, o
INVOKE<R>
(
fd,
std::
forward
<
V1
>
(
v1
)
,
std::
forward
<
V2
>
(
v2
)
, ...,
std::
forward
<
VN
>
(
vN
)
)
,
donde
fd
es un valor de tipo
std::
decay
<
F
>
::
type
, los valores y tipos de los argumentos vinculados
v1
,
v2
, ...,
vN
se determinan como se especifica
a continuación
.
Si algunos de los argumentos que se suministran en la llamada a g ( ) no coinciden con ningún marcador de posición almacenado en g , los argumentos no utilizados se evalúan y descartan.
Una invocación de
operator
(
)
es
no-lanzante
o es una
subexpresión constante
(desde C++20)
si y solo si lo es la operación subyacente
INVOKE
.
operator
(
)
participa en la resolución de sobrecarga solo si la operación
INVOKE
está bien formada cuando se trata como un operando no evaluado.
Si g está calificado como volatile , el programa está mal formado.
Si
INVOKE
(
fd, w1, w2, ..., wN
)
nunca puede ser una expresión válida para cualquier valor posible
w1
,
w2
, ...,
wN
, el comportamiento no está definido.
Argumentos vinculados
Para cada argumento almacenado
arg_i
, el argumento vinculado correspondiente
v_i
en la operación
INVOKE
o
INVOKE<R>
se determina de la siguiente manera:
Caso 1: reference wrappers
Si
arg_i
es de tipo
std::
reference_wrapper
<
T
>
(por ejemplo,
std::ref
o
std::cref
se utilizó en la llamada inicial a
std::bind
), entonces
v_i
es
arg_i.
get
(
)
y su tipo
V_i
es
T&
: el argumento almacenado se pasa por referencia al objeto función invocado.
Caso 2: expresiones bind
Si
arg_i
es de tipo
T
para el cual
std::
is_bind_expression
<
T
>
::
value
es
true
(por ejemplo, otra expresión
std::bind
se pasó directamente a la llamada inicial de
std::bind
), entonces
std::bind
realiza composición de funciones: en lugar de pasar el objeto función que devolvería la subexpresión bind, la subexpresión se invoca inmediatamente, y su valor de retorno se pasa al objeto invocable externo. Si la subexpresión bind tiene argumentos de marcador de posición, estos se comparten con el bind externo (seleccionados de
u1
,
u2
, ...
). Específicamente,
v_i
es
arg_i
(
std::
forward
<
Uj
>
(
uj
)
...
)
y su tipo
V_i
es
std::
result_of
<
T
cv
&
(
Uj
&&
...
)
>
::
type
&&
(hasta C++17)
std::
invoke_result_t
<
T
cv
&
, Uj
&&
...
>
&&
(desde C++17)
(la calificación cv es la misma que la de
g
).
Caso 3: placeholders
Si
arg_i
es de tipo
T
, para el cual
std::
is_placeholder
<
T
>
::
value
no es
0
(es decir, se utilizó un marcador de posición como
std::placeholders::_1, _2, _3, ...
como argumento en la llamada inicial a
std::bind
), entonces el argumento indicado por el marcador de posición (
u1
para
_1
,
u2
para
_2
, etc.) se pasa al objeto invocable:
v_i
es
std::
forward
<
Uj
>
(
uj
)
y su tipo
V_i
es
Uj&&
.
Caso 4: argumentos ordinarios
De lo contrario,
arg_i
se pasa al objeto invocable como argumento lvalue:
v_i
es simplemente
arg_i
y su tipo
V_i
es
T
cv
&
, donde
cv
es la misma calificación cv que la de
g
.
Excepciones
Solo lanza si la construcción de
std::
decay
<
F
>
::
type
desde
std::
forward
<
F
>
(
f
)
lanza, o cualquiera de los constructores para
std::
decay
<
Arg_i
>
::
type
desde el correspondiente
std::
forward
<
Arg_i
>
(
arg_i
)
lanza donde
Arg_i
es el i-ésimo tipo y
arg_i
es el i-ésimo argumento en
Args... args
.
Notas
Como se describe en Callable , 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 para bind son copiados o movidos, y nunca se pasan por referencia a menos que se envuelvan en std::ref o std::cref .
Se permiten marcadores de posición duplicados en la misma expresión de enlace (múltiples _1 por ejemplo), pero los resultados solo están bien definidos si el argumento correspondiente ( u1 ) es un lvalue o un rvalue no movible.
Ejemplo
#include <functional> #include <iostream> #include <memory> #include <random> void f(int n1, int n2, int n3, const int& n4, int n5) { std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n'; } int g(int n1) { return n1; } struct Foo { void print_sum(int n1, int n2) { std::cout << n1 + n2 << '\n'; } int data = 10; }; int main() { using namespace std::placeholders; // para _1, _2, _3... std::cout << "1) reordenamiento de argumentos y paso por referencia: "; int n = 7; // (_1 y _2 son de std::placeholders, y representan futuros // argumentos que se pasarán a f1) auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n); n = 10; f1(1, 2, 1001); // 1 está vinculado por _1, 2 está vinculado por _2, 1001 no se utiliza // realiza una llamada a f(2, 42, 1, n, 7) std::cout << "2) lograr el mismo efecto usando una lambda: "; n = 7; auto lambda = [&ncref = n, n](auto a, auto b, auto /*sin usar*/) { f(b, 42, a, ncref, n); }; n = 10; lambda(1, 2, 1001); // igual que una llamada a f1(1, 2, 1001) std::cout << "3) las expresiones de enlace anidadas comparten los marcadores de posición: "; auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5); f2(10, 11, 12); // realiza una llamada a f(12, g(12), 12, 4, 5); std::cout << "4) vincular un RNG con una distribución: "; std::default_random_engine e; std::uniform_int_distribution<> d(0, 10); auto rnd = std::bind(d, e); // una copia de e se almacena en rnd for (int n = 0; n < 10; ++n) std::cout << rnd() << ' '; std::cout << '\n'; std::cout << "5) enlazar a un puntero a función miembro: "; Foo foo; auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1); f3(5); std::cout << "6) vincular a un mem_fn que es un puntero a función miembro: "; auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum); auto f4 = std::bind(ptr_to_print_sum, &foo, 95, _1); f4(5); std::cout << "7) bind a un puntero a miembro de datos: "; auto f5 = std::bind(&Foo::data, _1); std::cout << f5(foo) << '\n'; std::cout << "8) enlazar a un mem_fn que es un puntero a miembro de datos: "; auto ptr_to_data = std::mem_fn(&Foo::data); auto f6 = std::bind(ptr_to_data, _1); std::cout << f6(foo) << '\n'; std::cout << "9) use smart pointers para llamar a miembros de los objetos referenciados: "; std::cout << f6(std::make_shared<Foo>(foo)) << ' ' << f6(std::make_unique<Foo>(foo)) << '\n'; }
Salida:
1) reordenamiento de argumentos y paso por referencia: 2 42 1 10 7 2) lograr el mismo efecto usando una lambda: 2 42 1 10 7 3) las subexpresiones de bind anidadas comparten los placeholders: 12 12 12 4 5 4) vincular un RNG con una distribución: 0 1 8 5 5 2 0 7 7 10 5) vincular a un puntero a función miembro: 100 6) vincular a un mem_fn que es un puntero a función miembro: 100 7) vincular a un puntero a miembro de datos: 10 8) vincular a un mem_fn que es un puntero a miembro de datos: 10 9) usar punteros inteligentes para llamar a miembros de los objetos referenciados: 10 10
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| LWG 2021 | C++11 |
1. los argumentos ligados
no se reenviaban a fd 2. en el caso 2, el tipo de
V_i
era
std:: result_of < T cv ( Uj... ) > :: type |
1. reenviados
2. cambiado a std:: result_of < T cv & ( Uj && ... ) > :: type && |
Véase también
|
(C++20)
(C++23)
|
enlaza un número variable de argumentos, en orden, a un objeto función
(plantilla de función) |
|
(C++11)
|
marcadores de posición para los argumentos no enlazados en una expresión
std::bind
(constante) |
|
(C++11)
|
crea un objeto función a partir de un puntero a miembro
(plantilla de función) |