2013-09-03 9 views
5

Per farla breve, esiste un modo semplice/definito per trattare gli oggetti funzione/lambdas e le funzioni membro in modo semplificato?Utilizzo di std :: function/mem_fn in C++ 11 con funzioni membro

Se ho capito bene, se uso std :: mem_fn, ho bisogno di passare un oggetto del tipo corretto per la chiamata di funzione, vale a dire

Object o; 
ftncall std::mem_fun(&Object::function); 
ftncall(o); 

Idealmente, ci sarebbe un modo per 'attaccare 'o per quell'oggetto funzione, forse come std::weak_ptr, quindi sappiamo se è stato cancellato. Ad esempio, se ci fosse un modo per fare qualcosa di vagamente simile a questo:

Object o; 
ftncall std::mem_fn(&Object::function, o); // Or maybe std::mem_fn<Object> 
ftncall(); 

Ora, ovviamente, questo non esiste (a mia conoscenza). C'è un modo per avvolgere std :: mem_fn in modo tale da non perdere la generalità (e la gentilezza) di std :: mem_fn, ma posso 'allegare' o, E giocare ancora bene con l'altro tipo di funzione, come std :: funzione? Idealmente, sarei ancora in grado di usare operator() nel modo in cui faccio con std :: function.

Attualmente la soluzione migliore che posso pensare è una classe che assomiglia a questo:

template<class T> 
class MemFunWrapper { 
public: 
    MemFunWrapper(T* t, std::mem_fun funct) : m_t(t), m_function(funct) {} 

    std::mem_fun operator*() { return m_function; } 
    T* get() { return m_t; } 
private: 
    T* m_t; 
    std::mem_fun m_function; 
} 

allora si potrebbe utilizzare questa convenzione:

(*MemFunWrapper)(MemFunWrapper->get(), args...); 

Ma che sembra abbastanza ingombrante per me. Inoltre, dovrei creare una classe equivalente per la funzione std :: per far sì che sia utilizzabile in modo analogo, e ciò sembra sciocco dal momento che posso già usare semplicemente std :: function. Idealmente, sarei anche in grado di utilizzare il prodotto finale senza sapere se sto chiamando una funzione membro o una funzione regolare. So che sto chiedendo molto - qualsiasi direzione sarebbe utile. Grazie molto!

risposta

10

Quello che stai cercando è std :: bind invece di std :: mem_fn:

#include <iostream> 
#include <functional> 

struct Object 
{ 
    void member() 
    { 
    std::cout << "yay!" << std::endl; 
    } 
}; 

int main() 
{ 
    Object o; 
    auto fn = std::bind(&Object::member, o); 
    fn(); 
} 

FWIW: C'è un proposal per l'aggiunta di un sovraccarico a std :: mem_fn accettare l'oggetto per l'inclusione in C++ 14.

+1

Perché grazie - potresti aver appena realizzato tutte le mie speranze e i miei sogni! –

+0

Non dovrebbe la riga 'auto fn = std :: bind (& Object :: member, o);' be 'auto fn = std :: bind (& Object :: member, &o);', attenzione al secondo argomento di 'std: : bind' –

+0

Dipende dalle tue intenzioni Entrambi sono utili in diverse circostanze – goji

8

In C++ 11, di solito trovo questo è più facile fatto con lambda:

std::shared_ptr<Object> o; 
auto ftncall = [o](){ if (o) o->function(); } 
ftncall(); 

Se avete bisogno di cancellazione del tipo, solo roba in una std::function<void()>.

Lambdas in C++ 11 può fare lo stesso lavoro di bind senza dover fare affidamento sulle funzioni di libreria per farlo, e personalmente le trovo molto più leggibili.

Ci sono alcune situazioni in cui bind può fare un lavoro migliore in C++ 11, ma sono casi d'angolo a questo punto (in C++ 1y, saranno tagliati anche più angoli).

+0

Solo per curiosità, potresti mostrarmi alcuni esempi 'std :: bind' è meglio in C++ 11? Ho riflettuto per un po 'di tempo ma potrei non lo trova. È collegato alla mancanza di lambda polimorfo? – Sungmin

+1

@ Sungmin 'bind' supporta l'inoltro perfetto, mentre i lambda no.Lambdas non può essere polimorfico, mentre 'bind' può. Un lambda ha un tipo di reso fisso: 'bind' potrebbe variare, se si passa a un functor con sovraccarichi multipli. "legare" supporta il wrapping dei funtori variarcici e il restante variardico, i lambda no. 'bind's può essere chiamato in contesti non valutati, come' decltype', utile per 'auto foo() -> decltype (bind (blah))': mentre il tipo è ottuso, non è magico come labmda. Quelli sono quelli che riesco a pensare in cima alla mia testa. Più della metà di essi sono andati in C++ 1y. – Yakk

+0

Anche incredibilmente utile - questo sembra 'più facile' come dici tu, ma è bello sapere che avrò ancora bisogno di usare 'bind' se userò funzioni polimorfiche - probabilmente la più probabile delle situazioni che potrebbero causare un problema per me almeno. –