Uso de objetos std::function genéricos con funciones miembro en una clase

Resuelto Christian Ivicevic asked hace 12 años • 6 respuestas

Para una clase, quiero almacenar algunos punteros de función a funciones miembro de la misma clase en un objeto mapque 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 argumentsen xxcallobjcombinació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

Christian Ivicevic avatar Sep 28 '11 18:09 Christian Ivicevic
Aceptado

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::functionfirma 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).

Alex B avatar Sep 28 '2011 11:09 Alex B

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);
Armen Tsirunyan avatar Sep 28 '2011 11:09 Armen Tsirunyan

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.

Greg avatar Nov 03 '2016 04:11 Greg