2015-12-14 19 views
6

con le seguenti funzionimodello Parametrizzazione dal nome della funzione C++ 11

void print(int a) { cout << a << endl; } 
void print(std::string a) { cout << a << endl; } 

È possibile effettuare le seguenti modello

template <class T> void printT(T a) { print(a); } 

C'è qualche meccanismo per parametrizzare il nome della funzione? Qualcosa di simile a questo:

template <class T, class F> void anyT(T a) { F(a); } 

Non ho bisogno di essere un modello di funzione, solo qualche meccanismo per ottenere lo stesso.

+1

Solo per curiosità: Perché vuoi farlo? Non è bello essere in grado di scrivere 'print (x);', dove 'x' può essere' string' o 'int', invece di dover specificare il tipo (ad esempio' print (x) 'per' int' e 'print (x)' per le stringhe)? – user463035818

+0

@ tobi303, non è necessario specificare il tipo di modello in questo caso. Il compilatore può facilmente dedurlo. – StoryTeller

+0

@ tobi303 Lo so. È solo un esempio di giocattolo per introdurre il problema e rendere le cose più facili a chi vuole aiutare. Odio davvero quando alcune persone incollano tutto il codice quando non è realmente necessario. –

risposta

1

Sì, si potrebbe passare il chiamante come un puntatore a funzione che prende come input T come di seguito:

template <class T> void anyT(T a, void(*f)(T)) { 
    f(a); 
} 

Live Demo

+0

L'elettore discendente spiega ... – 101010

+2

Non ho fatto un downvote, ma forse sarebbe meglio non specificare la firma del funzione e solo avere un parametro di modello per esso invece. In questo modo è possibile che la firma sia diversa ('const T &' ad esempio) e anche i functor saranno consentiti. – SirGuy

+0

Grazie !. Funziona perfettamente. –

0

fatica a comprendere la logica qui. In C++ 14 abbiamo lambda con argomenti automatici. Questo lo risolverà?

#include <iostream> 

int main() { 


    int a = 1; 
    std::string str = "string"; 

    auto print = [] (const auto& a) { std::cout << a << std::endl; }; 

    print(a); 
    print(str); 
} 
1

È possibile passare la funzione come parametro.

template <class T, class F> 
void anyT(T a, F f) { 
    f(a); 
} 

Il vantaggio di questo rispetto al passaggio di un puntatore funzione con template tipo di argomento proposto da 101010, è che questo funziona con puntatori alle funzioni nonché funtori (istanze di qualsiasi tipo che implementano operator() come lambda.

lo svantaggio è che ottenere un puntatore a funzione di una funzione di sovraccarico può essere difficile nel contesto del parametro liberamente su modelli. avresti bisogno di usare

void (*f)(int) = print; 
anyT(a, f); 

Oppure, in alternativa, avvolgerlo in un agnello da come proposto da GuyGreer.

1

Personalmente sceglierei la soluzione 101010, tuttavia sembra che non si desideri passare il puntatore alla funzione come parametro di funzione, ma solo come parametro di modello. Ecco come si può fare:

#include <string> 

    template <class T, void(*func)(T)> 
    void anyT(T t) 
    { 
     func(t); 
    } 

    void print(int i){} 
    void print(std::string s){} 

    int main() 
    { 
     anyT<int, print>(1); 
     anyT<std::string, print>("hello"); 
    } 

Purtroppo, significa che è necessario specificare i parametri del modello per la funzione di ogni tempo, che è un freno.

La soluzione migliore credo che sarebbe utilizzare solo un parametro di modello generico e un lambda:

template <class T, class F> 
    void anyT(T t, F f) 
    { 
     f(t); 
    } 

    auto printT = [](auto i){print(i);} 
    anyT(0, printT); 

La lambda è necessaria perché passando direttamente print sarebbe ambiguo, il compilatore non sa se si intende print(int) o print(std::string).

1

Questa è una macro utile:

#define OVERRIDES_OF(...) [](auto&&...args)->decltype(auto){ return __VA_ARGS__ (decltype(args)(args)...);} 

il risultato è una lambda stateless che inoltra al token fornito.

Usa:

static const auto printT = OVERRIDES_OF(print); 

ora printT è un oggetto che avvolge tutte le sostituzioni di print.

+0

Sembra che manchi un 'auto'. Indipendentemente da ciò, stai facendo in modo che la macro variadic supporti cose come 'OVERRIDES_OF (f <1,2,3>)'? Non riesco a pensare ad alcun altro motivo, ma immagino che possa anche chiedere. – SirGuy

+0

@guygreer puoi passare i set di override in giro come oggetti singoli con questa tecnica. Invece di dover specificare un override. – Yakk

+0

Set di override?Non sono sicuro di aver capito – SirGuy

0

È possibile passare la funzione tramite un puntatore a funzione:

template <class T> void anyT(T a, void(*F)(T)) { F(a); } 

ma poi non è possibile passare un lambda:

auto printStr = [](std::string a) { cout << a << endl; }; 
anyT(foo, printStr); // This won't compile 

Un approccio alternativo sarebbe quello di utilizzare std::function:

template <class T> 
void anyT(T a, std::function<void(T)> F) { F(a); } 

o un parametro di modello generico:

template <class T, class F> 
void anyT(T a, F func) { func(t); } 

Questo ha un inconveniente che non può risolvere funzioni sovraccaricate, ma è possibile utilizzare una funzione di supporto:

template<typename F> 
std::function<F> make_function(F *funPtr) { 
    return std::function<F>(static_cast<F*>(funPtr)); 
} 

e chiamare anyT come questo:

string foo = "foo"; 
anyT(foo, make_function<void(std::string)>(&print)); 
Problemi correlati