Modelli funzioni vs funzioni

Ho osservato alcuni dei codici sorgente di Boost e ho notato che implementano le funzioni basate su modelli utilizzando un functor invece di una funzione semplice? C’è una ragione per questo?

Per esempio:

template struct functor { Bar operator()(const Foo& foo) { return foo.as_bar(); } }; 

al contrario di:

 template Bar func(const Foo& foo) { return foo.as_bar(); } 

L’unico vantaggio che posso ricavare è che consente alle classi di ereditare la funzione?

Ci sono due ragioni principali: la prima è che, come notato dalla metafora pitonica, la specializzazione parziale è valida solo per le classi e non per le funzioni. Nota che le funzioni possono utilizzare gli overload per superare questo problema in generale, ma spesso se stai facendo metaprogrammazione è più facile e più generico usare la specializzazione parziale. In realtà pensavo che questa fosse la ragione principale.

La seconda ragione è che ogni volta che il codice vuole accettare un object funzione (come nel STL, ad es. Std :: transform), avrà un parametro template tipo. Se si passa un functor o un lambda, il tipo esatto è noto al momento della compilazione e non si paga per l’indirezione e si può eseguire l’inlining. Se si passa un puntatore a funzione (o una funzione std ::), solo la firma è nota al momento della compilazione e si paga per un riferimento indiretto (e non è ansible in linea). Ad esempio, std :: sort può essere considerevolmente più veloce con un functor rispetto a un puntatore a funzione.

Si noti che esiste una funzione poco utilizzata denominata parametri del modello del puntatore della funzione; questi sono parametri di template non di tipo specializzati su una funzione specifica, e quindi in grado di rimuovere l’indirezione. Tuttavia, se si utilizza uno di questi, non è ansible utilizzare un functor. Quindi la maggior parte del codice che vuole accettare un object funzione lo fa come descritto sopra.