Uso de objetos std::function genéricos con funciones miembro en una clase
Para una clase, quiero almacenar algunos punteros de función a funciones miembro de la misma clase en un objeto map
que almacene std::function
. Pero fallo desde el principio con este código:
#include <functional>
class Foo {
public:
void doSomething() {}
void bindFunction() {
// ERROR
std::function<void(void)> f = &Foo::doSomething;
}
};
Recibo error C2064: term does not evaluate to a function taking 0 arguments
en xxcallobj
combinación con algunos errores extraños de creación de instancias de plantillas. Actualmente estoy trabajando en Windows 8 con Visual Studio 2010/2011 y en Win 7 con VS10 también falla. El error debe basarse en algunas reglas extrañas de C++ que no sigo
Se debe llamar a una función miembro no estática con un objeto. Es decir, siempre pasa implícitamente "este" puntero como argumento.
Debido a que su std::function
firma especifica que su función no toma ningún argumento ( <void(void)>
), debe vincular el primer (y único) argumento.
std::function<void(void)> f = std::bind(&Foo::doSomething, this);
Si desea vincular una función con parámetros, debe especificar marcadores de posición:
using namespace std::placeholders;
std::function<void(int,int)> f = std::bind(&Foo::doSomethingArgs, this, std::placeholders::_1, std::placeholders::_2);
O, si su compilador admite lambdas de C++ 11:
std::function<void(int,int)> f = [=](int a, int b) {
this->doSomethingArgs(a, b);
}
(No tengo a mano un compilador compatible con C++ 11 en este momento , así que no puedo verificar este).
O necesitas
std::function<void(Foo*)> f = &Foo::doSomething;
para que pueda llamarlo en cualquier instancia, o necesita vincular una instancia específica, por ejemplothis
std::function<void(void)> f = std::bind(&Foo::doSomething, this);
Si necesita almacenar una función miembro sin la instancia de clase, puede hacer algo como esto:
class MyClass
{
public:
void MemberFunc(int value)
{
//do something
}
};
// Store member function binding
auto callable = std::mem_fn(&MyClass::MemberFunc);
// Call with late supplied 'this'
MyClass myInst;
callable(&myInst, 123);
¿ Cómo sería el tipo de almacenamiento sin auto ? Algo como esto:
std::_Mem_fn_wrap<void,void (__cdecl TestA::*)(int),TestA,int> callable
También puede pasar el almacenamiento de esta función a un enlace de función estándar.
std::function<void(int)> binding = std::bind(callable, &testA, std::placeholders::_1);
binding(123); // Call
Notas pasadas y futuras: Existía una interfaz más antigua std::mem_func , pero desde entonces ha quedado obsoleta. Existe una propuesta, posterior a C++ 17, para hacer que el puntero a funciones miembro sea invocable . Esto sería muy bienvenido.