c++ - Usando std:: bind con la función de miembro, use el puntero del objeto o no para este argumento?
c++11 language-lawyer (3)
Al usar std::bind
para enlazar una función miembro, el primer argumento es el objeto this
puntero. Sin embargo, funciona pasando el objeto como un puntero y no como.
Ver por ejemplo el siguiente programa:
#include <iostream>
#include <functional>
struct foo
{
void bar(int v) { std::cout << "foo::bar - " << v << ''/n''; }
};
int main()
{
foo my_foo;
auto f1 = std::bind(&foo::bar, my_foo, 1);
auto f2 = std::bind(&foo::bar, &my_foo, 2);
f1();
f2();
}
Tanto clang como GCC compilan esto sin quejas, y el resultado funciona para ambos enlaces:
foo::bar - 1 foo::bar - 2
He estado tratando de ajustarme a la especificación (sección 20.8.9), pero es uno de los lugares donde no está nada claro para mí.
¿Debería uno solo ser correcto, o ambos son correctos?
Ambos son correctos. 20.8.9.1.2 reenvía a 20.8.2 para describir los requisitos y el efecto de su llamada para bind
. 20.8.2 es:
20.8.2 Requisitos [func.require]
1 Defina INVOKE
(f, t1, t2, ..., tN)
siguiente manera:-
(t1.*f)(t2, ..., tN)
cuandof
es un puntero a una función miembro de una claseT
yt1
es un objeto de tipoT
o una referencia a un objeto de tipoT
o una referencia a un objeto de un tipo derivado deT
;-
((*t1).*f)(t2, ..., tN)
cuandof
es un puntero a una función miembro de una claseT
yt1
no es uno de los tipos descritos en el elemento anterior;-
t1.*f
cuandoN == 1
yf
es un puntero a los datos de miembro de una claseT
yt1
es un objeto de tipoT
o una referencia a un objeto de tipoT
o una referencia a un objeto de un tipo derivado deT
;-
(*t1).*f
cuandoN == 1
yf
es un puntero a los datos de miembros de una claseT
yt1
no es uno de los tipos descritos en el elemento anterior;-
f(t1, t2, ..., tN)
en todos los demás casos.
Las primeras dos opciones permiten tanto una referencia como un puntero.
Lo importante que debe tener en cuenta aquí es que la redacción no lo limita a simples indicaciones. Podría usar std::shared_ptr
u otro puntero inteligente para mantener viva su instancia mientras está encuadernada y aún así funcionaría con std::bind
ya que t1
se desreferencia, no importa de qué se trate (dado, por supuesto, que es posible) .
Hay una diferencia. Como dice rytis, al pasar por valor no se ven los cambios realizados en my_foo. Por ejemplo, en caso de que my_foo sea una clase, al pasar por valor no se ve un cambio en los datos de miembro de my_foo.
Para agregar a la respuesta correcta (que ambos formularios están permitidos).
Pienso en las dos opciones de enlace en analogía con la declaración de argumento de función, que puede ser "pasado por valor" o "pasado por referencia".
En el caso de f1
(también conocido como pasar my_foo
"por valor"), el resultado no "ve" ningún cambio realizado en my_foo
allá del punto de enlace. Esto puede no ser deseado especialmente si my_foo
evoluciona. El enlace "Por valor" tiene un "costo" adicional de (varias) llamadas a un constructor de copia.