Funzione di modello come un modello argomento

Io ho solo confuso come implementare qualcosa in modo generico in C++. È un pò contorto, quindi lasciatemi spiegare passo per passo.


Considerare tale codice:

void a(int) {
    //do something
}
void b(int) {
    //something else
}


void function1() {
    a(123);
    a(456);
}
void function2() {
    b(123);
    b(456);
}

void test() {
    function1();
    function2();
}

È facilmente evidente che function1 e function2 fare lo stesso, con l’unica parte diversa essendo la funzione interna.

Quindi, voglio fare function generico per evitare la ridondanza del codice. Posso farlo utilizzando i puntatori a funzione o modelli. Mi permetta di scegliere la seconda, per ora. Il mio pensiero è che è meglio dato che il compilatore sarà sicuramente in grado di inline funzioni – ho capito bene? Può compilatori ancora inline chiamate se sono effettuate tramite puntatori a funzione? Questo è un lato domanda.

OK, torniamo al punto iniziale… Una soluzione con i modelli:

void a(int) {
    //do something
}
void b(int) {
    //something else
}

template<void (*param)(int) >
void function() {
    param(123);
    param(456);
}

void test() {
    function<a>();
    function<b>();
}

Tutto OK. Ma io sono in esecuzione in un problema: posso ancora fare che se a e b sono generici stessi?

template<typename T>
void a(T t) {
   //do something
}

template<typename T>
void b(T t) {
   //something else
}

template< ...param... > //???
void function() {
    param<SomeType>(someobj);
    param<AnotherType>(someotherobj);
}

void test() {
    function<a>();
    function<b>();
}

So che un parametro di modello può essere:

  • un tipo,
  • un tipo di modello,
  • un valore di un tipo.

Nessuno di quelli che sembra coprire la mia situazione. La mia domanda è quindi: Come faccio a risolvere che, cioè definire function() nell’ultimo esempio?

(Sì, i puntatori a funzione sembra essere una soluzione in questo caso preciso, a patto che può anche essere inline – ma sto cercando una soluzione generale di questa classe di problemi).

InformationsquelleAutor Kos | 2011-01-15



4 Replies
  1. 27

    Al fine di risolvere questo problema con i modelli, è necessario utilizzare un modello di parametro del modello.
    Purtroppo, non è possibile passare template template di funzione come un tipo, perché deve essere istanziato prima. Ma c’è una soluzione con un manichino strutture. Qui è un esempio:

    template <typename T>
    struct a {
    
        static void foo (T = T ())
        {
        }
    
    };
    
    template <typename T>
    struct b {
    
        static void foo (T = T ())
        {
        }
    
    };
    
    struct SomeObj {};
    struct SomeOtherObj {};
    
    template <template <typename P> class T>
    void function ()
    {
        T<SomeObj>::foo ();
        T<SomeOtherObj>::foo ();
    }
    
    int main ()
    {
        function<a>();
        function<b>();
    }
    • Non esattamente perché questo ha downvoted. Non è del tutto soddisfacente, ma che non risolve il problema.
    • Quindi, per riassumere: l’unica soluzione che permetterebbe a in linea chiamate a sostituire le funzioni con functors? Un po ‘ ingombrante, ma del tutto accettabile, credo. Grazie!
    • Ma ammetto che sono molto sorpreso dopo aver detto che non è possibile inline un indirizzo di chiamata… Se l’indirizzo non può essere determinato in fase di compilazione per essere uguale ad un dato indirizzo della funzione, mi sarei aspettato che il compilatore sia abbastanza intelligente. 🙂 Strano…
    • Ho avuto una corsa con g++ 4.5 e ottenuto contrario risultati: pastebin.com/eXbAyLPv
    • il test è troppo semplice, gcc è abbastanza intelligente per ottimizzare semplice statica blocchi di codice. Di provare qualcosa di più vicino alla realtà. BTW, non ha senso specificare -O3 e -Os allo stesso tempo. Se si utilizza più O opzioni, con o senza numeri di livello, l’ultima opzione è quella che è efficace.
    • Davvero semplice, ma è quello che volevo sapere – se l’utilizzo di un riferimento indiretto a forma di puntatore a funzione viene ottimizzato o meno quando la funzione è noto. Grazie per le info sui flag di ottimizzazione, ho pensato che in qualche modo agire insieme, in termini di esatta applicata -f bandiere.
    • Devo dire, Vlad, che è bellissimo, ma wth, funziona e si adatta il disegno di legge.
    • In C++14 si potrebbe usare un generico espressioni lambda per generare quelle chiusure: rende il codice un po ‘ più breve e non richiede template template argomenti.

  2. 0

    Ecco un modo. Potrebbe non essere il massimo, ma funziona:

    template <typename T, T param>
    void function() {
        param(123);
        param(456);
    }
    
    void test()
    {
        function< void(*)(int), a<int> >(); //space at end necessary to compiler
        function< void(*)(int), b<int> >(); //because the C++ grammar is ambiguous
    }

    Se o non saranno sostituite dipende dal compilatore, ma sarei molto sorpreso se non lo erano.

    EDIT: Ok, mi sono un po ‘ fuori di oggi e di perdere la parte in cui i parametri sono di diversi tipi. Il mio cattivo.

    Ci può essere un modo difficile per fare questo con i modelli, ma questo è il modo più semplice che ho potuto pensare:

    #define function(x) do { x<thing1>(obj1); x<thing2>(obj2) } while(0)

    So, lo so, “le macro sono il male”, bla bla bla. Funziona. Se function deve essere più complicato di quanto il vostro esempio, si può incorrere in problemi, ma è molto più facile di quanto avessi mai stato in grado di venire con.

    • Ma si prega di notare che function si desidera chiamare diverse istanze del parametro di funzione di modello.
    • È #define fuori questione?
    • Beh, è “last resort”, che dovrebbe funzionare :), ma è a disagio a modificare, eseguire il debug, non può essere in uno spazio dei nomi… io preferisco trovare un modello di base non preprocessore a base di soluzione.
  3. 0

    Con lambda dal C++11, si potrebbe fare:

    template<typename T> void a(T t) { /* do something */}
    template<typename T> void b(T t) { /* something else */ }
    
    template <typename F>
    void function(F&& f) {
        f(someobj);
        f(someotherobj);
    }
    
    void test() {
        //For simple cases, auto&& is even probably auto or const auto&
        function([](auto&& t){ a(t); });
        function([](auto&& t){ b(t); });
    
        //For perfect forwarding
        function([](auto&& t){ a(std::forward<decltype(t)>(t)); });
        function([](auto&& t){ b(std::forward<decltype(t)>(t)); });
    }

    Può compilatori ancora inline chiamate se sono effettuate tramite puntatori a funzione?

    Si può, ma è davvero più complicato, e si potrebbe non riuscire più spesso che con funtore o modello.

  4. -2
    template < typename F >
    void function(F f)
    {
      f(123);
    }
    
    void a(int x) { ... }
    
    struct b { void operator() (int x) { ... } };
    
    void outer()
    {
      function(&a);
      function(b());
    }
    • Questo non è ciò che l’OP voleva.
    • Grazie, ma questo non è correlato con il problema che ho descritto. In questo caso, è un dato di function chiamata utilizza solo 1 istanza di una funzione di parametro/funtore. Si prega di leggere la domanda, ancora una volta.

Lascia un commento