2011-09-28 12 views
100

Per una classe, desidero memorizzare alcuni puntatori di funzioni alle funzioni membro della stessa classe in uno map memorizzando oggetti std::function. Ma non riesco proprio all'inizio con questo codice:Utilizzo di oggetti generici std :: function con funzioni membro in una classe

class Foo { 
    public: 
     void doSomething() {} 
     void bindFunction() { 
      // ERROR 
      std::function<void(void)> f = &Foo::doSomething; 
     } 
}; 

ricevo error C2064: term does not evaluate to a function taking 0 arguments in xxcallobj combinato con alcuni errori istanziazione di template strani. Attualmente sto lavorando su Windows 8 con Visual Studio 2010/2011 e su Win 7 con VS10. L'errore deve essere basato su alcune strane regole C++ che non seguo.

MODIFICA: lo faccio NON aumento di utilizzo. Questo è C++ 11 integrato nel compilatore MS.

+0

La risposta corretta è utilizzare 'std :: invoke', che non è supportato da MSVC2013. Questa domanda è un po 'datata. – Mikhail

risposta

180

una funzione di membro non statico deve essere chiamato con un oggetto Cioè, passa sempre implicitamente "questo" puntatore come argomento.

Perché la tua firma std::function specifica che la funzione non richiede alcun argomento (<void(void)>), è necessario legano il primo (e l'unico) argomento.

std::function<void(void)> f = std::bind(&Foo::doSomething, this); 

Se si desidera associare una funzione con parametri, è necessario specificare i segnaposto:

using namespace std::placeholders; 
std::function<void(int,int)> f = std::bind(&Foo::doSomethingArgs, this, _1, _2); 

Oppure, se il compilatore C++ supporta 11 lambda:

std::function<void(int,int)> f = [=](int a, int b) { 
    this->doSomethingArgs(a, b); 
} 

(Non ho un compilatore compatibile con C++ 11 a portata di mano al momento, quindi non posso controllare questo.)

+1

Siccome non sono dipendente da boost, userò espressioni lambda;) Comunque grazie! –

+3

@AlexB: Boost.Bind non utilizza ADL per i segnaposti, ma li inserisce in uno spazio dei nomi anonimo. – ildjarn

+11

Si consiglia di evitare l'acquisizione globale [=] e utilizzare [this] per rendere più chiaro ciò che viene catturato (Scott Meyers - Effective Modern C++ Capitolo 6. elemento 31 - Evita le modalità di acquisizione predefinite) –

53

O avete bisogno

std::function<void(Foo*)> f = &Foo::doSomething; 

in modo che si può chiamare in qualsiasi istanza, o hai bisogno di impegnare una specifica istanza, ad esempio this

std::function<void(void)> f = std::bind(&Foo::doSomething, this); 
3

Se è necessario memorizzare una funzione membro senza l'istanza della classe, si può fare qualcosa di simile:

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); 

Quale sarebbe il tipo di archiviazione assomigliare senza auto? Qualcosa di simile a questo:

std::_Mem_fn_wrap<void,void (__cdecl TestA::*)(int),TestA,int> callable 

È inoltre possibile passare questo stoccaggio funzione per una funzione standard vincolante

std::function<void(int)> binding = std::bind(callable, &testA, std::placeholders::_1); 
binding(123); // Call 

passato e note future: Una vecchia interfaccia std :: mem_func esistito, ma da allora stato deprecato. Esiste una proposta, post C++ 17, per rendere pointer to member functions callable. Questo sarebbe molto gradito.

+0

@Danh 'std :: mem_fn' era ** non ** rimosso; un mucchio di inutili sovraccarichi. D'altra parte 'std :: mem_fun' è stato deprecato con C++ 11 e verrà rimosso con C++ 17. –

+0

@Danh Questo è esattamente ciò di cui sto parlando;) Il primo overload "di base" è ancora lì: 'template mem_fn non specificato (RT :: *);', e non andrà lontano. –

+0

@Danh Leggi [il DR] (https://cplusplus.github.io/LWG/lwg-defects.html#2048) attentamente. 12 su 13 sovraccarichi sono stati rimossi dal DR. Quest'ultimo * non era * (e non lo sarebbe, né in C++ 11 né in C++ 14). –

Problemi correlati