En fait, le cas d'utilisation des paramètres de gabarit est assez évident. Une fois que vous avez appris que la stdlib C++ a un trou béant en ne définissant pas les opérateurs de sortie de flux pour les types de conteneurs standard, vous pouvez écrire quelque chose comme :
template<typename T>
static inline std::ostream& operator<<(std::ostream& out, std::list<T> const& v)
{
out << '[';
if (!v.empty()) {
for (typename std::list<T>::const_iterator i = v.begin(); ;) {
out << *i;
if (++i == v.end())
break;
out << ", ";
}
}
out << ']';
return out;
}
Vous vous apercevrez alors que le code pour vector est le même, pour forward_list est le même, en fait, même pour une multitude de types de cartes, c'est toujours le même. Ces classes de modèles n'ont rien en commun à l'exception de la méta-interface/du protocole, et l'utilisation d'un paramètre de modèle de modèle permet de capturer les points communs à toutes ces classes. Avant de procéder à l'écriture d'un modèle, il est utile de vérifier une référence pour se rappeler que les conteneurs de séquence acceptent deux arguments de modèle - pour le type de valeur et l'allocateur. Bien que l'allocateur soit proposé par défaut, nous devons tout de même tenir compte de son existence dans notre opérateur de gabarit<< :
template<template <typename, typename> class Container, class V, class A>
std::ostream& operator<<(std::ostream& out, Container<V, A> const& v)
...
Voilà, cela fonctionnera automatiquement pour tous les conteneurs de séquence présents et futurs qui adhèrent au protocole standard. Pour ajouter les cartes au mélange, il suffirait de jeter un coup d'œil à la référence pour noter qu'elles acceptent 4 paramètres de modèle, nous aurions donc besoin d'une autre version de l'opérateur<< ci-dessus avec un paramètre de modèle de 4args. Nous verrions également que std:pair essaie d'être rendu avec un opérateur<< à 2 arguments pour les types de séquence que nous avons définis précédemment, nous fournirions donc une spécialisation juste pour std::pair.
Par ailleurs, avec C+11 qui autorise les modèles variadiques (et qui devrait donc autoriser les arguments variadiques des modèles), il serait possible d'avoir un seul opérateur<< pour les dominer tous. Par exemple :
#include <iostream>
#include <vector>
#include <deque>
#include <list>
template<typename T, template<class,class...> class C, class... Args>
std::ostream& operator <<(std::ostream& os, const C<T,Args...>& objs)
{
os << __PRETTY_FUNCTION__ << '\n';
for (auto const& obj : objs)
os << obj << ' ';
return os;
}
int main()
{
std::vector<float> vf { 1.1, 2.2, 3.3, 4.4 };
std::cout << vf << '\n';
std::list<char> lc { 'a', 'b', 'c', 'd' };
std::cout << lc << '\n';
std::deque<int> di { 1, 2, 3, 4 };
std::cout << di << '\n';
return 0;
}
Sortie
std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = float, C = vector, Args = <std::__1::allocator<float>>]
1.1 2.2 3.3 4.4
std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = char, C = list, Args = <std::__1::allocator<char>>]
a b c d
std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = int, C = deque, Args = <std::__1::allocator<int>>]
1 2 3 4
5 votes
I s