5 votes

Pouvez-vous utiliser les modèles C++ pour spécifier un type de collection et la spécialisation de ce type ?

Exemple, je veux spécialiser une classe pour avoir une variable membre qui est un conteneur stl, par exemple un vecteur ou une liste, donc j'ai besoin de quelque chose comme :

template <class CollectionType, class ItemType>
class Test
{
public:
    CollectionType<ItemType> m_collection;
};

Je peux donc le faire :

Test  t = Test<vector, int>();
t.m_collection<vector<int>> = vector<int>();

Mais cela génère

test.cpp:12: error: `CollectionType' is not a template

15voto

Luc Touraille Points 29252

Ce que vous voulez, c'est un paramètre de modèle :

template <template <typename> class CollectionType, class ItemType>
class Test
{
public:
    CollectionType<ItemType> m_collection;
};

Ce que nous avons fait ici, c'est spécifier que le premier paramètre du modèle, c'est-à-dire CollectionType est un modèle de type. Par conséquent, Test ne peut être instancié qu'avec un type qui est lui-même un modèle.

Cependant, comme @Binary Worrier l'a souligné dans les commentaires, cela ne fonctionnera pas avec les conteneurs STL puisqu'ils ont 2 paramètres de modèle : l'un pour le type d'éléments, l'autre pour le type d'allocateur utilisé pour gérer l'allocation de stockage (qui a une valeur par défaut).

Par conséquent, vous devez modifier le premier paramètre du modèle pour qu'il ait deux paramètres :

template <template <typename,typename> class CollectionType, class ItemType>
class Test
{
public:
    CollectionType<ItemType> m_collection;
};

Mais attendez, ça ne marche pas non plus ! En effet, CollectionType attend un autre paramètre, l'allocateur... Vous avez donc maintenant deux solutions :

1 . Imposer l'utilisation d'un allocateur particulier :

CollectionType<ItemType, std::allocator<ItemType> > m_collection

2 . Ajoutez un paramètre de modèle pour l'allocateur dans votre classe :

template <template <typename,typename> class CollectionType, 
          class ItemType,
          class Allocator = std::allocator<ItemType> >
class Test
{
public:
    CollectionType<ItemType, Allocator> m_collection;
};

Comme vous le voyez, on se retrouve avec quelque chose d'assez compliqué, qui semble vraiment tordu pour traiter les conteneurs STL...

Mon conseil : consultez la réponse de Greg Rogers pour une meilleure approche :) !

13voto

Greg Rogers Points 18119

Pourquoi ne pas le faire de cette manière ?

template <class CollectionType>
class Test
{
public:
    CollectionType m_collection;
};

Test  t = Test<vector<int> >();
t.m_collection = vector<int>();

Si vous avez besoin du type d'article, vous pouvez utiliser CollectionType::value_type .

EDIT : en réponse à votre question sur la création d'une fonction membre renvoyant le value_type, vous procédez comme suit :

typename CollectionType::value_type foo();

Vous ajoutez le nom de type parce que CollectionType n'a pas encore été lié à un type réel. Il n'y a donc pas de value_type qu'il pourrait rechercher.

2voto

tragomaskhalos Points 1085

Comeau online aime cela :

#include <vector>

template <template <class T, class A = std::allocator<T> > class CollectionType, class ItemType>
class Test
{
public:
    CollectionType<ItemType> m_collection;
};

void foo()
{
using std::vector;
Test<vector,int>  t = Test<vector, int>();
t.m_collection = vector<int>();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X