2012-12-10 9 views
6

So che questa domanda è stata posta prima, ma nonostante sia un programmatore esperto non capisco le risposte e non vedo modo di rispondere a queste domande precedenti per chiedere una precisazione. Non esiste un collegamento "risposta" o altro. Inoltre, quelle domande erano piuttosto vecchie. Quindi, sto facendo di nuovo la domanda.Come sovraccaricare su std: firma di funzione in C++

Ho una classe, in cui sovraccarico l'operatore + =. Voglio un sovraccarico di prendere un puntatore a funzione nuda, e l'altro di prendere una std :: funzione:

void operator+=(void (*handler)()); 
void operator+=(function<void (void *, T)> handler); 

Usage:

MyClass a; 
a += [](){ DoSomething(); }; 
a += [](void *x, T y){ DoSomething(); }; 

Purtroppo, il codice non viene compilato perché il compilatore non è in grado di determinare che il secondo sovraccarico non è adatto per la prima + = chiamata.

Come definire il mio operatore + = funzioni membro per correggere questo problema? Non voglio cambiare il modo in cui vengono utilizzati gli operatori (ad esempio utilizzando un cast esplicito). Voglio che funzionino come dimostrato sopra.

Inoltre, sarebbe utile avere il seguente overload così:

void operator+=(function<void()> handler); 

Ma ancora una volta, non può sovraccaricare in base alla firma della funzione <> modello.

Vedere questo thread per ulteriori esempi: Isn't the template argument (the signature) of std::function part of its type? (ho provato attuazione delle diverse soluzioni menzionate in quel filo, e nessuno di essi compilazione)

Sono stato di programmazione per molti anni in numerosi lingue, ma le mie competenze in C++ sono un po 'arrugginite.

+0

la domanda ** big ** è: __Che hai intenzione di fare con un puntatore a funzione dato o un oggetto 'std :: function' nel tuo overload' operatore + = '? __ – zaufi

+0

@zaufi: Non riesco a vedere come è rilevante, ma va bene. Lo aggiungerò a un std :: vector delle funzioni del gestore di eventi. Sto essenzialmente implementando eventi .NET in C++. Perché i Poteri che Sono non hanno ancora bloccato la testa sul fatto che Eventi e Proprietà sono - come le Chiusure - funzionalità assolutamente essenziali per un linguaggio di programmazione moderno. –

+0

quindi, devi avere un 'std :: vector' istanziato con' std :: function' con uno esacly (suggerisco 'void()') signature ... Ho ragione? – zaufi

risposta

3

Seguendo codice funziona bene con g ++ 4.7.2:

#include <functional> 
#include <iostream> 

template <typename T> 
typename std::enable_if<std::is_convertible<T, void(*)()>::value>::type 
foo(T&&) 
{ 
    std::cout << "foo(void(*)())" << std::endl; 
} 

void foo(std::function<void(void*,int)>) 
{ 
    std::cout << "foo(std::function<void(void*,int)>)" << std::endl; 
} 

int main() 
{ 
    foo([]{}); 
    foo([](void*,int){}); 
} 

Il problema è causato dal costruttore di std::function, che viene dichiarato come template <class F> function(F);. Quel costruttore accetta tutto come argomento. Se questo argomento non ha uno operator() appropriato, viene generato un errore durante l'istanziazione del costruttore.

Sfortunatamente il processo di risoluzione del sovraccarico non richiede l'istanziazione di alcuna funzione modello, pertanto il compilatore ritiene che tutto possa essere convertito in qualsiasi tipo di std::function.

+0

Grazie, sono quasi riuscito a farlo entrare nella mia classe senza problemi; anche se le cose erano un po 'pelose quando ho provato a lanciare T su una funzione <>. Sembra che devo prima lanciarlo su un void (*)(). Saluti. –

+0

Penso che il problema principale che ho avuto è che non ho mai sentito parlare di enable_if e non lo capisco. Ero vagamente consapevole del fatto che poteva essere d'aiuto (guardando le risposte a domande simili), ma non sapevo come fosse usato. Non sono ancora sicuro di come funzioni. –

+0

Alcune informazioni su 'enable_if' possono essere trovate [qui] (http://www.boost.org/doc/libs/1_52_0/libs/utility/enable_if.html) e [qui] (http: //en.cppreference .com/w/cpp/tipi/enable_if). – hpsMouse

0

Ok, se hai un std::vector<std::function<void()>> non hai nemmeno bisogno di avere un sacco di sovraccarichi. Il modo più semplice è definire un modello operator+=, possibile "protetto" con std::enable_if da attivare solo per oggetto richiamabile o puntatori di funzione. Così passando lambda o puntatori grezzi farà la conversione automatica per te su assign (push_back/emplace_back). Il passaggio std::function assegnerà solo come previsto.

+0

Ti manca il punto. Voglio aggiungere sia "[]() {}" lambda e "[] (void *, T) {}" lambda al mio vettore. Li avvolgo in una classe contenitore comune e li aggiungo al mio vettore. Cercare di convincermi che non ho bisogno di diverse firme lambda è un inutile spreco del tuo tempo e del mio. –