Pagine    Articoli    Prodotti    Forum    Cerca  
Nickname

Password


Non sei registrato?
Registrati a GPI qui!

Puoi anche attivare un vecchio utente GPI e chiedere una nuova password.
I Team

Mappa Team
I nostri utenti

Mappa Utenti
  C++11: Template variadics e concorrenza
Pubblicato da Dario Oliveri il 2013-02-03 21:50:09

Quale miglior modo di mostrare le nuove features del C++ che con qualche semplice esempio alla portata di tutti?

 

Sebbene siano passati già due anni dalla definizione del nuovo standard (e sebbene alcune features siano in realtà degli affinamenti di librerie già esistenti, per lo più prese da "boost" ). La maggior parte dei compilatori non ha ancora finito di implementare il C++11 per intero. A quando un'implementazione completa e stabile?

 

 

Creare un thread (c++11)


#include  < thread >
#include  < iostream >

void foobar() //funzione che verrà chiamata in parallelo
{
    std::cout << "Ciao Mondo!" << std::endl;
}

int main()
{
    thread td1(foobar);
    td1.join(); //attende termine del thread prima di uscire
    return 0;
}

 

 

Non credo servano particolari commenti al codice, è molto intuitivo già così com'è.

 

Passare argomenti alla funzione del Thread (c++11)

 

#include < thread >
#include < iostream >

void print_sum(int a, int b)
{
    std::cout << "risultato:" << a+b << std::endl;
}


int main()
{
    thread td2 (print_sum,3,5);
    td2.join(); 
    return 0;
}

//output :  "risultato: 8"

 

 

 

Qualche nota: il fatto di poter scrivere prima il nome della funzione e poi gli argomenti solamente separati da una virgola, è possibile grazie ai "variadic templates", senza questi infatti sarebbe stato necessario passare un oggetto di tipo "ParameterList". L'utilità è immediatamente visibile, senza i "variadic templates" il codice sarebbe stato scritto così:

 

#include < thread >
#include < iostream >
#include "ParameterList.hpp"

void print_sum( ParameterList params)
{
    int a = params.pop_int();
    int b = params.pop_int();
    std::cout << "risultato: " << a + b << std::endl;
}

int main()
{
    ParameterList params;
    params.push_int(3);
    params.push_int(5);
    thread td3(print_sum, params);
    td3.join();
    return 0;
}

 

 

 

Ovviamente il codice così è molto più verboso e noioso, inoltre insorge lo stesso problema che abbiamo in alcuni linguaggi di scripting come il Lua: Chi ci assicura che il numero di "push" sia uguale al numero di "pop"? (senza contare poi che devono avere il tipo giusto, se fosse stato un numero floating point? servivano "push_back_float" e "pop_float").

 

Con i template variadics viene risolto questo problema permettendo di scrivere tutto in una sola riga di codice e come se non bastasse il risultato è già ottimizzato.

 

Come funzionano i  template variadici?

Supponiamo di voler una funzione che stampi a schermo una qualunque combinazione di valori.

 

int main()
{
    print(3,5.6,"hello",'c');
    print("ciao!");
    return 0;
}

 

Ora si può fare!

 

#include < iostream >

template < class BASE, class...ARGS >
void print( BASE first, ARGS ...all)
{
    std::cout << first << " ";
    print(all...);
}


int main()
{
    print("ciao",5,4,3);
    return 0;
}

 

 

Direi che è inutile stare a spiegare come funziona la sintassi, la questione è complessa e piena di sfumature, però può essere utile andare a vedere cosa succede nel dettaglio:

 

#include < iostream >


template < class BASE, class ...ARGS >
void debug_print( BASE first, ARGS ...all)
{
    std::cout << first << " ";
    debug_print(all...);
}


template < class BASE, class ...ARGS >
void print( BASE first, ARGS ...all)
{
    std::cout << "\nStampo parametro:" << first << std::endl;
    std::cout << "Parametri rimasti:" << sizeof...(ARGS)   
    std::cout << "I parametri rimasti sono: " << std::endl;
    debug_print(all...);
    print(all...);
}

int main()
{
    print("ciao",5,4,3);
    return 0;
}

 

 

 

 

Spero che come infarinatura di base basti, è necessario avere un po di dimestichezza con i templates. Basti pensare che sono un applicazione del "principio di induzione". Le due funzioni in particolare hanno una lista di argomenti variabile che ad ogni chiamata ricorsiva si riduce di 1. Nessuno vietava di ridurre il numero di argomenti di 2 alla volta (ma ci sarebbe stato il problema che veniva accettato solo un numero pari di parametri).

 

template < class BASE1, class BASE2, class ...ARGS >
void print( BASE1 first, BASE2 second, ARGS... all)
{
    std::cout << first << " " << second << " " << std::endl;
    print(all...);
}

 

Limitazioni?

 

Qualcuna. Si tratta di una risoluzione a compile-time, significa che non è possibile sfruttare questo meccanismo con interfacce basate su codice pre-compilato(librerie). Non sarà possibile avere classi polimorfiche che accettino un numero di parametri variabile, per queste la soluzione resterà usare un oggetto di tipo "ParameterList" (infatti la nuova classe thread è una classe templates, non è precompilata!).

 

Dal punto di vista dell'object oriented design, il nuovo C++ offre qualcosina di nuovo, ma lo fa per mettersi in pari con altri linguaggi fornendo le parole chiave "final, override, nullptr". La vera novità sta nelle run-time unificate (finalmente una classe thread indipendente dal sistema operativo! anche se qui altri linguaggi la offrivano già) e nei templates.

Campagne crowfunding

Just One Line
Siamo presenti su

     
Copyright ©2016 - Manifesto - Privacy - Termini di Servizio - Community - Collaboratori - Contattaci