Riferimenti di funzione

Quindi stavo solo lavorando con i puntatori di funzione e mi sono ricordato che potevi fare questo:

void Foo() { } int main() { void(& func)() = Foo; func(); //::Foo(); } 

L’ovvio vantaggio è che i riferimenti fanno riferimento a oggetti validi (a meno che non vengano utilizzati in modo improprio) o funzioni in questo caso.

Gli svantaggi evidenti sono che non è ansible memorizzare una matrice di riferimenti e non è ansible utilizzarli per i puntatori di funzioni dei membri (almeno per quanto posso dire).

La mia domanda: qualcuno li usa (vale a dire, riferimenti alle funzioni , non puntatori di funzione), e in tal caso, in quali scenari li hai trovati utili / utili?

L’unico posto in cui riesco a vederli utili è il collegamento a una determinata funzione quando si lavora con la compilazione condizionale.

Li ho usati prima per aggiungere la personalizzazione alle classi passandole al costruttore in un modo simile al modello di strategia

Penso che il tuo utilizzo di esempio sia abbastanza buono. Perché se si utilizza un puntatore di funzione ordinario e si applica quindi l’operatore address-of, si otterrà l’indirizzo del puntatore della funzione. L’uso di un riferimento alla funzione farà la cosa prevista, in quanto restituisce un puntatore alla funzione stessa.

Inoltre non riesco a pensare a molti esempi. Mantenere i riferimenti alle funzioni, come lei sottolinea, ha delle brutte conseguenze. Un’altra conseguenza potenzialmente indesiderata è che, se conservati come membri della class, i tuoi oggetti non saranno assegnabili se non scrivi il tuo operatore = e non tenterai di riassegnare il riferimento alla funzione.

Penso che la maggior parte degli usi dei riferimenti alle funzioni siano impliciti, proprio come la maggior parte degli usi dei riferimenti a matrice – anche se molto più, quando si accettano argomenti per riferimento:

 template void do_something(T const& t) { ... } 

Mentre accettare gli array per riferimento ha il vantaggio di non perdere le informazioni sulle dimensioni, accettare le funzioni in base a un riferimento esplicito non sembra avere un vantaggio (almeno per quanto posso vedere). Suppongo che l’esistenza di riferimenti di funzioni sia ampiamente giustificata dalla visione idealistica di un riferimento come un alias -name di qualche object o funzione, insieme al fatto che esso consente di passare funzioni a tali template che accettano il loro argomento per riferimento.

Probabilmente eviterei di usarli se non ne avessi bisogno inevitabilmente. I puntatori a funzioni costanti forniscono anche callable non riassegnabili e probabilmente eviteranno confusioni quando altri programmatori, che probabilmente non conoscono bene le nicchie linguistiche, leggono il codice. Vale la pena notare che Vandervoorde e Josuttis consigliano anche di evitarli per ridurre la confusione (nel loro manuale C ++ Templates – The Complete Guide).

I riferimenti alle funzioni, a differenza dei puntatori di funzione, rendono più difficile crearli da una fonte non valida. Ciò è utile se stai facendo un wrapper attorno ad una libreria C – il codice C ++ può prendere una funzione di callback per riferimento e passare il puntatore alla libreria C se il lbrary richiede che il puntatore passato non debba essere NULL.

È anche un modo conveniente per creare un alias di una funzione, specialmente in C ++ 11 con la nuova parola chiave auto:

 #include  #include  void f(int i, char c) { std::cout << i << ' ' << c << std::endl; } int main() { std::cout << typeid(f).name() << std::endl; //FvicE f(0, '1'); void (*pf)(int, char) (&f); //ugly std::cout << typeid(pf).name() << std::endl; //PFvicE (*pf)(2, '3'); pf(4, '5'); //works, but I don't recommend it void (&rf)(int, char) (f); //still ugly std::cout << typeid(rf).name() << std::endl; //FvicE rf(6, '7'); auto &af (f); //pretty, but only works in C++11 std::cout << typeid(af).name() << std::endl; //FvicE, same as above af(8, '9'); } 

Li ho usati in un sistema plug-in in cui le DLL dei plug-in potevano essere caricate / scaricate in fase di esecuzione. Cercherò i simboli noti in ogni DLL e li getterò ai puntatori di funzione.

oltre all’uso come strategia (come indicato da Robert Gould), li uso freqentemente al punto di ingresso per la metaprogrammazione (modello). Un riferimento alla funzione può essere facilmente rilevato da un parametro del template; da questo punto in poi può essere passato attraverso diversi livelli di modelli (metaprogrammazione). Naturalmente, ciò vale anche per un puntatore a funzione, ma il riferimento è un alias e quindi comunica più chiaramente l’intenzione.

Per fare un esempio: quando si scrive un sistema di distribuzione di comandi generici per un’applicazione, è necessario annunciare come comandi molte operazioni diverse. Possiamo utilizzare una semplice “funzione builder” come front-end per il codice client. Dietro le quinte, questa funzione builder acquisisce la firma della funzione effettiva come parametro del modello, ricava (mediante metaprogrammazione del modello) il parametro effettivo e restituisce i valori del tipo ed eventualmente seleziona la specializzazione adatta per memorizzare un “memento” e un “undo functor”. Questi funtori possono essere memorizzati come puntatori di funzioni internamente oppure usando gli oggetti funzione boost o tr1 o C ++ 11. In questo modo, è ansible creare un invocazione di comando di tipo safe e “undo”.

Probabilmente puoi usare std :: reference_wrapper per usare il riferimento nel contenitore.

In questo modo, ottieni tutto il reference adventage e puoi utilizzarlo come valore.

Sono stato coinvolto in un progetto che intendeva implementare un sistema Object in C utilizzando i puntatori di funzione e le strutture per implementare le classi. Dal momento che le funzioni potrebbero essere sostituite, potrebbero implementare una sorta di sistema di ereditarietà. Fortunatamente, questo sforzo si è interrotto. Mentre il compito era interessante, non era una buona idea per il progetto (probabilmente non è una buona idea per qualcosa in produzione).

Ho anche usato i puntatori di funzione per un sistema di moduli pluggable basati su DLL, come menzionato prima.