web-dev-qa-db-fra.com

Classe de modèle avec conteneur de modèle

Comment puis-je déclarer une classe de modèle (adaptateur) avec différents conteneurs comme arguments de modèle? Par exemple, je dois déclarer la classe:

template<typename T, typename Container>
class MyMultibyteString
{
    Container buffer;
    ...
};

Et je le veux à mon basé sur le vecteur. Comment le définir durement? (pour empêcher quelqu'un d'écrire une telle déclaration MyMultibyteString<int, vector<char>>).

De plus, comment mettre en œuvre une telle construction:

MyMultibyteString<int, std::vector> mbs;

sans passer d'argument de modèle au conteneur.

35
DuXeN0N

Vous devez utiliser les paramètres de modèle de modèle :

template<typename T, template <typename, typename> class Container>
//                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
class MyMultibyteString
{
    Container<T, std::allocator<T>> buffer;
    // ...
};

Cela vous permettrait d'écrire:

MyMultibyteString<int, std::vector> mbs;

Voici un exemple de compilation live . Une autre façon d'écrire ce qui précède pourrait être:

template<typename T,
    template <typename, typename = std::allocator<T>> class Container>
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
class MyMultibyteString
{
    Container<T> buffer; // <== No more need to specify the second argument here
    // ...
};

Et voici l'exemple en direct correspondant .

La seule chose à laquelle vous devez faire attention est que le nombre et le type d'arguments dans la déclaration de paramètre de modèle de modèle doivent correspondre exactement au nombre et au type d'arguments dans la définition du modèle de classe correspondant que vous souhaitez passer comme argument de modèle, indépendamment du fait que certains de ces paramètres peuvent avoir des valeurs par défaut.

Par exemple, le modèle de classe std::vector accepte deux paramètres de modèle (le type d'élément et le type d'allocateur), bien que le second ait la valeur par défaut std::allocator<T>. Pour cette raison, vous pourriez ne pas écrire:

template<typename T, template <typename> class Container>
//                             ^^^^^^^^
//                             Notice: just one template parameter declared!
class MyMultibyteString
{
    Container<T> buffer;
    // ...
};

// ...

MyMultibyteString<int, std::vector> mbs; // ERROR!
//                     ^^^^^^^^^^^
//                     The std::vector class template accepts *two*
//                     template parameters (even though the second
//                     one has a default argument)

Cela signifie que vous ne pourrez pas écrire un seul modèle de classe pouvant accepter les deux std::set et std::vector comme paramètre de modèle de modèle, car contrairement à std::vector, les std::set le modèle de classe accepte trois paramètres de modèle .

72
Andy Prowl

Une autre approche pour résoudre ce problème consiste à utiliser des modèles variadiques et avec lesquels vous pouvez utiliser n'importe quel conteneur comme suggéré dans les commentaires ci-dessus et voici l'implémentation:

template<template <typename... Args> class Container,typename... Types>
class Test
{
    public:
    Container<Types...> test;

};
int main()
{
  Test<std::vector,int> t;
  Test<std::set,std::string> p;
  return 0;
}
8
Kapil