Je veux avoir une fonction de modèle en C++, où un paramètre de modèle est lui-même un modèle d'un autre paramètre de modèle. Si cela n'a aucun sens, prenez le code suivant qui affiche un vecteur std :: qui est basé sur un modèle de type T
template <typename T>
void print_vector(std::vector<T> &vec)
{
for(auto v: vec)
std::cout << v << " ";
std::cout << std::endl;
}
...
std::vector<double> vec(5);
...
print_vector(vec);
Je veux généraliser davantage cette fonction pour les conteneurs STL autres que vector. Mais je ne sais pas comment "imbriquer" les paramètres du modèle de telle sorte que le conteneur soit basé sur le type T. J'ai essayé ce qui suit sans succès
template <typename T, template <typename TT> V>
void print_container(V<T> &con)
{
for(auto c: con)
std::cout << c << " ";
std::cout << std::endl;
}
...
std::vector<double> vec(5);
...
print_container(vec);
Je suis sûr que cela a déjà été répondu ici, mais je ne trouve pas les termes de recherche pour trouver la réponse.
MODIFIER : Merci @ForEveR, votre réponse était juste sur l'argent! Toutes les réponses à ma question ont permis de constater qu'il n'est pas nécessaire de modéliser le type "stockage" T, la solution suivante étant adéquate pour l'exemple que j'ai donné:
template <typename C>
void print_container(C &con)
{
for(auto v: con)
std::cout << v << " ";
std::cout << std::endl;
}
Malheureusement, le cas d'utilisation réel qui a motivé la question était un peu plus compliqué. La routine prend plusieurs conteneurs, comme cet exemple d'algèbre linéaire avec une matrice et une classe vectorielle:
template <typename MATRIX, typename VECTOR>
void mat_vec_multiply(const MATRIX &A, const VECTOR &x, VECTOR &y)
{
// implement y = A*x;
}
Supposons que les classes MATRIX et VECTOR doivent être calquées sur la même classe de stockage sous-jacente (c'est-à-dire double, float, int ...). L'idée est qu'en spécifiant explicitement T comme paramètre de modèle, nous pouvons appliquer ceci:
template < typename T,
template<typename> class MATRIX,
template<typename> class VECTOR>
void mat_vec_multiply(const MATRIX<T> &A, const VECTOR<T> &x, VECTOR<T> &y)
{
// implement y = A*x;
}
Malheureusement, j'utilise le compilateur CUDA nvcc, qui ne prend pas en charge les constructions C++ 11 (je viens d'utiliser C++ 11 dans mon exemple car il est moins verbeux). Je ne peux donc pas utiliser std :: is_same et static_assert, bien que je suppose que je pourrais rouler mon propre is_same (ou utiliser BOOST) assez facilement. Quelle est la "meilleure pratique" dans ce cas, où je souhaite appliquer le paramètre de modèle commun pour les classes de stockage?
std::vector
a deux paramètres, type et allocateur. Essaye ça
template <typename T, typename Alloc, template <typename, typename> class V>
void print_container(V<T, Alloc> &con)
{
}
print_container(vec);
Cela fonctionnera pour vector
, list
, etc., mais ne fonctionnera pas avec map
, set
.
Cependant, puisque vous utilisez auto
, vous pouvez utiliser C++ 11, puis vous pouvez le faire:
template <typename T, template <typename, typename...> class V, typename... Args>
void print_container(V<T, Args...> &con)
ou
template <template <typename, typename...> class V, typename... Args>
void print_container(V<Args...> &con)
et bien sûr le moyen le plus simple est de faire quelque chose comme
template<typename C>
void print_container(C& con)
probablement avec quelques vérifications pour déduire, que C
est vraiment un conteneur.
template<typename C>
auto print_container(C& con) -> decltype(con.begin(), void())
Il vaut mieux ne pas faire ça du tout; considérez simplement les modèles sur le conteneur
template <typename C>
void print_container(const C& container)
{
for(auto v: container)
std::cout << v << " ";
std::cout << std::endl;
}
Si vous avez besoin du type stocké dans la fonction, vous pouvez utiliser: `typedef typename C :: value_type T;
Je ne suis pas sûr d'avoir compris ce que vous voulez mais vous pouvez essayer ceci:
template <typename V>
void print_vector(V &vec)
{
for(auto v: vec)
std::cout << v << " ";
std::cout << std::endl;
}
...
std::vector<double> vec(5);
...
print_vector(vec);
Le point ici est que vous n'avez généralement pas besoin de construire comme template < template V< typename T> >
parce que le modèle entier template V< typename T>
peut être généralisé pour taper V
.