Rechercher
 

Utilisation du mot clé typename en C++

Vous le savez déjà, le mot clé typename permet de spécifier les types génériques utilisés par un template : template <typename T>, par exemple. Néanmoins, il existe une autre forme d'utilisation du mot clé typename : la définition d'un autre type de données, lui-même basé sur un des types génériques utilisé par le template.

Afin de mieux comprendre ce cas d'utilisation, imaginons une liste de chaîne de caractères triées : nous souhaitons définir une fonction générique d'ajout de valeur dans cette liste, mais à la bonne position étant donné que la liste est triée. Mais, contrairement aux bonnes pratiques de la STL, nous souhaitons que cette fonction utilise directement la collection et non pas des itérateurs sur cette collection. Dans ce cas, nous allons rencontrer un problème de compilation que nous ne pourrons résoudre que grâce à l'utilisation du mot clé typename.

Effectivement, il nous faudra bien, à un moment, définir une variable locale définie comme étant un itérateur sur le type de collections considéré. Dans l'exemple ci-dessous, le type sera typename COLLECTION::iterator : si nous ne le préfixons pas du mot clé typename, le compilateur refusera d'aller plus loin. Si, au contraire, vous l'utilisez, alors le compilateur saura qu'il ne pourra déduire ce type que et uniquement que lorsqu'il connaitra le type réel de COLLECTION.

#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>
#include <string>

using namespace std;


template< typename COLLECTION, typename T >
void sorted_insert( COLLECTION & collection, const T & value) {
    typename COLLECTION::iterator begin = collection.begin();
    typename COLLECTION::iterator end = collection.end();
    while( begin != end ) {
        if ( value < *begin ) break;
        begin++;
    }
    collection.insert( begin, value );
}



int main( int argc, char * argv[] ) {

    list<string> languages;

    languages.push_back( "Python" );
    languages.push_back( "C" );
    languages.push_back( "C++" );
    languages.push_back( "C#" );
    languages.push_back( "Perl" );
    languages.sort();

    sorted_insert( languages, "Java" );
    for( const string & language : languages ) {
        cout << language << " ";
    }    
    cout << endl;

    return 0;
}

/*
 * For compile this sample with g++ :
 * $> g++ -std=c++11 -o Sample Sample.c
 */

Vous l'avez peut être remarqué, le codage ci-dessus présuppose que vous utilisiez un compilateur compatible avec le standard C++11 (utilisation du for sur collection). Pour les utilisateurs de g++, exécutez la ligne de commande suivante : g++ -std=c++11 -o Sample Sample.cpp. Pour tout autre compilateur, vérifiez qu'il soit compatible C++11 au niveau de sa documentation.

Enfin, notez que cette possibilité de syntaxe peut aussi être nécessaire à différents autres endroits et notamment lors de la définition d'attributs ou de typedefs au sein d'une classe template.