Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 67 di 93
  • livello avanzato
Indice lezioni

Introduzione ai template

Introduzione all'uso dei template in C++, che permettono di usare un'unica funzione generica per vari tipi di dato, nello stile della metaprogrammazione.
Introduzione all'uso dei template in C++, che permettono di usare un'unica funzione generica per vari tipi di dato, nello stile della metaprogrammazione.
Link copiato negli appunti

Uno degli aspetti più interessanti ed "esoterici" del C++ è la presenza di un sistema di metaprogrammazione. Esso permette di eseguire delle operazioni a tempo di compilazione, ad esempio, effettuando delle elaborazioni del codice sorgente. In prevalenza, le istruzioni di metaprogrammazione operano sui tipi.

Poiché in C++ vige il controllo statico dei tipi, normalmente è necessario definire a priori il tipo delle variabili usate come argomenti di una funzione o come membri di classe. Ciò può rendere necessario duplicare porzioni di codice al solo scopo di adattarne l'impiego a tipi diversi, contravvenendo al principio fondamentale di riuso del codice.

Si consideri come esempio il listato seguente, in cui le funzioni swap_integers e swap_strings sono sostanzialmente identiche, ad eccezione del tipo delle variabili che hanno per argomento.

#include <iostream>
#include <string>
 
using std::string;
 
void swap_integers(int& a, int& b)
{
    int tmp = a;
    a = b;
    b = tmp;
}
 
void swap_strings(string& a, string& b)
{
    string tmp = a;
    a = b;
    b = tmp;
}
 
int main()
{
    int i1 = 2;
    int i2 = 6;
     
    swap_integers(i1, i2);
    std::cout << i1 << ", " << i2 << "\n";
     
    string s1("hello");
    string s2("world");
     
    swap_strings(s1, s2);
    std::cout << s1 << ", " << s2 << "\n";
     
    return 0;
}

La parola chiave template viene usata in C++ per indicare una unità di codice "generica", ad esempio una funzione o una classe, la cui implementazione può essere adatta a molteplici tipologie di dato. Facendo ricorso alla metaprogrammazione, quindi, è possibile collassare la definizione delle due funzioni di swap in un'unica entità, valida per ogni tipo, come mostrato nel listato seguente:

#include <iostream>
#include <string>
 
using std::string;
 
template <typename T>
void swap_generic(T& a, T& b)
{
    T tmp = a;
    a = b;
    b = tmp;
}
 
int main()
{
    int i1 = 2;
    int i2 = 6;
     
    string s1("hello");
    string s2("world");
     
    swap_generic(i1, i2);
    std::cout << i1 << ", " << i2 << "\n";
    swap_generic(s1, s2);
    std::cout << s1 << ", " << s2 << "\n";
     
    return 0;
}

Il preambolo costituito dalla parola chiave template seguita da una lista di parametri typename NomeTipo tra parentesi angolari viene apposto ad una funzione swap_generic() per qualificarla come funzione generica.

In fase di compilazione, ogni qualvolta viene individuata l'invocazione di una funzione generica, il compilatore applica le regole di inferenza per definire il corretto valore da attribuire al parametro NomeTipo (T in questo esempio) ed aggiunge al codice sorgente originale un sovraccarico di tale funzione in cui il parametro generico è sostituito da un tipo specifico.

Tale processo viene definito istanziazione di template ed avviene prima alla compilazione vera e propria.

Per l'esempio in questione, il risultato di questa elaborazione è molto simile al primo listato in cui esistono due funzioni diverse per interi e stringhe, con la differenza che tale operazione viene espletata dal compilatore generando un overload diverso della funzione swap_generic() per ogni tipo di variabile cui essa viene applicata, in questo caso int e std::string.

Programmazione generica e metaprogrammazione

Questa modalità di impiego dei template in C++ è un'esempio di programmazione generica. Sebbene essa sia una delle principali applicazioni dei template, non esaurisce le possibilità offerte dalla metaprogrammazione in C++.

A differenza di altri linguaggi orientati alla programmazione ad oggetti (OOP), la definizione di template in C++ costituisce di fatto un linguaggio di programmazione a sé.

Mediante la definizione di template è possibile far eseguire al compilatore istruzioni condizionali ed elaborazioni ricorsive di complessità arbitraria. Ciò significa che il sistema di metaprogrammazione di C++ è Turing-completo.

Sebbene questa sia una caratteristica estremamente affascinante, raramente è di utilità pratica, nel senso non è necessario ricorrere alle caratteristiche avanzate di metaprogrammazione in C++ per codificare un qualsiasi algoritmo.

Ciò nonostante, le librerie standard fanno ampio uso della metaprogrammazione per la definizione di API di base molto flessibili ed efficienti. In effetti, l'uso di template nella STL è pressoché ubiquitario, ed è divenuto imprescindibile con l'avvento dello standard C++11.

Esistono inoltre numerosi design pattern che si avvalgono del sistema di templating in C++ per realizzare implementazioni estremamente efficienti e resilienti.

In conclusione, acquisire una conoscenza di base del sistema di metaprogrammazione è essenziale per comprendere le funzionalità evolute del C++ moderno e consente anche di comprendere le ragioni che hanno motivato le innovazioni introdotte dagli standard più recenti ed i possibili sviluppi futuri della programmazione in C++.

Ti consigliamo anche