6
votes

Modèles et stl

Le code suivant représente un conteneur basé sur std :: vecteur xxx

est-il possible de templatiser std :: Vector et de créer un conteneur général, quelque chose comme ça? < Pré> xxx

où stl_container représente std :: vecteur, std :: liste, std :: set ...? Je voudrais choisir le type de conteneur au moment de la création. xxx

merci pour vos réponses ...

Question mise à jour:

J'ai essayé ce qui suit code mais il y a des erreurs: xxx


2 commentaires

Qui utiliserait cette classe? Pourquoi ne peut pas list il suffit d'utiliser typéfef vecteur / liste / définir <élément> éléments ? Quel serait le but d'une classe qui, étant donné un type de conteneur et un type de valeur, met simplement ces deux ensemble?


Re: Le Modifier, je ne vois toujours pas pourquoi vous ne pouvez pas écrire list > liste; etc.


6 Réponses :


5
votes

oui et non.

Vous pouvez utiliser un paramètre de modèle de modèle, par exemple xxx

Toutefois, en général, les paramètres de modèle de modèle ne sont pas particulièrement utiles car le nombre et les types de paramètres de modèle doivent correspondre. Donc, ce qui précède ne correspondrait pas std :: vecteur car il dispose de deux paramètres de modèle: une pour le type de valeur et une pour l'allocator. Un paramètre modèle de modèle ne peut pas tirer parti des arguments de modèle par défaut.

Pour pouvoir utiliser le modèle std :: vecteur comme argument, TLIST devrait être déclaré comme: xxx

Cependant, avec ce modèle, vous ne pourriez pas utiliser le std :: map Modèle comme argument car il a quatre paramètres de modèle: Types de la clé et de la valeur, du type d'allocator et du type de comparateur.

Habituellement, il est beaucoup plus facile d'éviter les paramètres de modèle de modèle à cause de cette inflexibilité.


9 commentaires

Pourriez-vous remplacer Modèle Conteneur de classe avec juste Typename conteneur et accédez au type contenu dans le conteneur à l'aide de conteneur :: valeur_type ?


@Billy: Bien sûr; Chaque conteneur a un valeur_type Typef. Cependant, cela ne vous permettra pas de créer le conteneur, qui est ce que l'OP est question.


@James: ah - je vois. On dirait que l'OP a besoin de certains itérateurs alors :)


Bien sûr, il suffit de regarder ce que STD :: Stack fait!


@Bo: Eh bien, std :: pile ne prend pas de modèle, il faut un type de conteneur. C'est-à-dire qu'il ne faut pas std :: deque , il faut std :: deque .


Étant donné que le vecteur et la carte sont résolument différents types de conteneurs, qui partagent très peu d'une portée d'utilisation, le problème que vous mentionner me semble être un problème pratique.


@Crazy: Eh bien, j'ai choisi std :: map car il est apparu dans la liste de l'OP et dispose d'une liste de paramètres de modèle qui ne correspond pas au paramètre std :: vecteur liste. C'est toujours un problème, même pour les conteneurs de séquence: tandis que tous les conteneurs de séquence de bibliothèque standard (à l'exception du tableau TRAY in c ++ 0x) ont deux paramètres de modèle de type ( t et alloc ), il n'est pas nécessaire que d'autres conteneurs définis par l'utilisateur ont exactement deux paramètres de modèle de type; Un conteneur défini par l'utilisateur peut avoir des paramètres de modèle plus ou moins ou différents.


@Crazy: Puissons std :: Set Ensuite, non associatif, et encore 3 paramètres au lieu du 2 de std :: vecteur .


@Matthieu M. M. - J'espère que vous ne pensez pas que ces deux conteneurs sont interchangeables.



0
votes

est-il possible de templatiser std :: Vector et de créer un conteneur général, quelque chose comme ça?

non. Vous devriez templatiser la fonction ou l'objet en utilisant le conteneur - vous ne pouviez pas templatiser le conteneur lui-même.

Par exemple. Considérons un std :: Recherche : xxx

Ceci fonctionne pour n'importe quel conteneur, mais n'a pas besoin d'une tempalte avec le conteneur du tout. < / p>

Également, étant donné qu'il ressemble à ce que vous essayez de faire est de faire du code indépendant du conteneur, vous voudrez peut-être vous acheter ou emprunter une copie de Scott Meyers ' efficace STL et lisez l'élément 2: Méfiez-vous de l'illusion du code indépendant du conteneur.


4 commentaires

Les algorithmes n'entraînent-ils que des itérateurs, plutôt que des conteneurs / gammes partiellement la cause de l'impossibilité du code indépendant du conteneur? IT est possible d'écrire une fonction de recherche générique, qui fonctionne également efficacement pour la définition et la carte, mais pas avec cette signature.


@Unclebens: Oui - L'article de STL efficace décourage à ne pas essayer d'utiliser uniquement des fonctionnalités que tous les conteneurs STL fournissent, de sorte qu'ils puissent les éteindre. (Meyers est préférable à expliquer que moi) si vous pouvez templatiser un algorithme au moyen d'un modèle, alors par tous les moyens. (Mais vous aurez probablement besoin de quelques spécialisations de modèles si vous voulez que ce soit le plus efficace pour les conteneurs séquentielles et associatifs;))


En ce qui concerne l'élément 2: méfiez-vous l'illusion du code indépendant du conteneur, n'est-ce pas la plupart des algorithmes de STL sous cet esprit?


@Kirakun: Les algorithmes sont mis en œuvre en termes d'itérateurs et non de conteneurs.



2
votes

Eh bien, vous pouvez le pirater avec une macro:

template <typename T, typename stl_container = std::vector<T> >
struct TList
{
    typedef stl_container Type;
};

#define TLIST(T, C) TList<T, C<T> >

TList<int> foo;
TList<int, std::list<int> > bar;
TLIST(int, std::list) baz;


1 commentaires

Cuz je suis un amoureux de chat ;-). Mais oui, c'est un hack.



11
votes

Oui, mais pas directement: xxx pré>

alors vous pouvez définir différentes stratégies de conteneur: p> xxx pré>

un peu verbeuse, cependant. * Faire des choses directement, vous auriez besoin de prendre L'itinéraire décrit par James , mais Comme il le note, cela est finalement très inflexible. P>

Cependant, avec C ++ 0x, nous pouvons le faire tout simplement bien: P>

template <typename T, typename Container>
struct rebind; // not defined

template <typename T, typename Container, typename... Args>
struct rebind<T, Container<Args...>>
{
    // assumes the rest are filled with defaults**
    typedef Container<T> type; 
};


11 commentaires

Bonne idée. Y a-t-il un problème qui ne peut-il pas être résolu avec une couche supplémentaire d'indirection?


@James: Nope. Je peux même voir mon front si j'utilise un miroir.


Lol - c'est soigné. Et les commentaires sont hilarants. +1.


Pour la ligne TypeDef Typename Conteneur

:: Type Type; Compiler a déclaré: Erreur C2059: Erreur de syntaxe: '<', erreur C2238: jeton inattendu (s) précédent (s) ';'


@ROBO: Je n'ai pas cette ligne. (Vous avez :: Type pendant que j'ai :: Type .) Dans tous les cas, quel code êtes-vous compilé?


@Gman> J'ai placé votre code dans ma question, voir ci-dessus, s'il vous plaît. Je pensais :: Type était une surveillance ...


@ROBO: Oh oui, désolé, faute de frappe dans ma réponse. Fixé. (Notez votre code posté dans la question omits mapp_container , cependant.) (Et @dowvoter: Commentaire? Impossible de réparer les choses si je ne sais pas ce qui ne va pas.)


@Gman. Merci de votre réponse ... J'ai somnolent et je n'ai pas remarqué votre dernier commentaire :-) La première option est suffisante ... demain je vais essayer (éventuellement) revenir.


Et avec des alias de modèle, vous pouvez écrire modèle à l'aide de REBIND = Typename Détail :: Rebind :: Type; .


Je ne suis pas suivant comment vous allez sur les choses dans le bloc de code suivant les mots "Cependant, avec C ++ 0x, nous pouvons le faire juste bien:". Le moyen évident de faire est d'utiliser des modèles TypeDef. Cela ne ressemble pas à ce que vous faites, cependant. La fonctionnalité que vous pouvez ajouter des arguments de modèle de trailing arbitariat en C ++ 0x? Si oui, pouvez-vous ajouter une référence, s'il vous plaît? Merci.


Ah, je vois. Vous utilisez Modèles VARIADIC ici, non? Donc, cela peut être résolu par l'un ou l'autre modèle TypeDefs ou les modèles variadiques, on dirait. Qui sont des opérations complémentaires, d'une certaine manière. On vous permet de réduire le nombre de modèles, l'autre vous permet de les prolonger. :-)



6
votes

Je suis un peu perplexe Pourquoi des personnes très intelligentes (et compétentes) disent non.

sauf si j'ai mal interprété votre question, ce que vous essayez d'accomplir est pratiquement identique aux "adaptateurs de conteneurs" dans la bibliothèque standard. Chacune fournit une interface à certains types de conteneurs sous-jacents, le type de conteneur qui sera utilisé fourni sous forme de paramètre de modèle (avec une valeur par défaut).

Par exemple, un std :: pile utilise un autre conteneur (par exemple, std :: deque , std :: Liste ou std :: vecteur ) pour maintenir les objets, et std :: pile lui-même fournit simplement une interface simplifiée / restreinte lorsque vous souhaitez simplement utiliser des opérations de pile. Le conteneur sous-jacent qui sera utilisé par le std :: pile est fourni sous forme de paramètre de modèle. Voici comment le code regarde dans la norme: xxx

Bien sûr, je n'ai peut-être pas mal compris la question - si oui, je m'excuse d'avance aux personnes avec qui je 'm (sorte de) désaccord.


10 commentaires

Jerry: le code OP veut écrire comme myClass pour créer un std :: vecteur . Dans l'exemple STD :: Stack EXEMPLE, le numéro de code transduit n'est pas std :: deque , c'est std :: deque - Pas un modèle de classe, mais une classe de modèle. C'est-à-dire que votre code aboutirait à l'OP à faire myClass > .


@Billy O'Neal: J'ai relu la question et je ne trouve toujours pas où il dit que c'est ce qu'il veut. Peut-être que je n'ai tout simplement pas suffisamment de sommeil la nuit dernière ou quelque chose que ....


Je pense que le point de la question était d'obtenir le conteneur sans passer de type entier dans le paramètre de modèle. (Par exemple, je peux donc faire le type de valeur secret_type

.) Mais je pense que votre réponse est également importante puisque nous devrions résoudre des problèmes et non seulement répondre aux questions, et c'est la meilleure façon de répondre à la plupart des questions. nous y allions.


@Jerry: Voir la deuxième boîte de Code de l'OP. (Regarde le typlef là-bas)


@Gman: C'est peut-être ce qu'il veut, mais je ne trouve rien dans la question qui semble le dire. Mon impression était simplement qu'il voulait quelque chose comme un adaptateur de conteneur, lui permettant de brancher un conteneur sous-jacent différent lorsque / s'il voit en forme.


@Billy O'Neal: Je l'ai regardé. Je ne peux pas voir où il fait beaucoup pour soutenir votre position cependant.


@Jerry: Afin de compiler, le typename stl_container devrait être un modèle de modèle (comme dans @james ') répondre.


J'ai lu la question de la même manière @gman. Il est tout à fait possible que je lis ça faux, cependant. Cette solution est, imo, la solution la plus naturelle.


@Billy O'Neal: Mais même s'il s'agissait d'un modèle de modèle, cela ne compilerait toujours pas. Un typlef doit ressembler à quelque chose comme typedef Somenye somename; Ce qu'il a est (au mieux) juste Typefef-sentatype; , sans nom pour le typeDEF. Je pense que beaucoup trop de travail est en train de mettre en place une syntaxe très spécifique, quand tout ce qu'il semble (à moi) est à faire, c'est essayer de représenter l'idée générale que l'intérieur de sa classe, le type de conteneur sous-jacent sera transmis comme paramètre.


@James McNellis: Eh bien, je suppose qu'à ce stade, peu importe beaucoup. Il a maintenant des réponses qui couvrent à la fois des possibilités (et que c'est ce que la réponse de l'OP ou non, la réponse de Gman est assez cool).



-1
votes

Vous pouvez utiliser des paramètres de modèle de modèle, car d'autres ont mentionné ici. La principale difficulté avec ceci n'est pas que les types de conteneurs dissemblables ont des paramètres de modèle différents, mais que la norme permet aux conteneurs standard, comme le vecteur, de disposer de paramètres de modèle en plus des paramètres documentés, nécessaires.

Vous pouvez déplacer cela par Fournir à vos propres types de sous-classe qui acceptent les paramètres de modèle appropriés et que tous les extras (qui doivent avoir des paramètres par défaut) sont remplis dans ma mise en œuvre: xxx

ou vous pouvez utiliser le modèle Typedef idiom: xxx


3 commentaires

La norme C ++ ne permet pas à une implémentation d'avoir des paramètres de modèle supplémentaires et facultatifs.


Je doute parce que vous héritez de conteneurs standard. Ils n'ont pas de destructeur virtuel, il est donc dangereux d'utiliser votre classe simple_vector dans des endroits où vous vous attendriez à un vecteur ; Les utilisateurs de la classe pourraient (et volonté) le faire mal et laisser vecteur :: ~ vecteur être appelé au lieu de simple_vector :: ~ simple_vector .


Pas dans ce cas Alexandre. Donnez-vous un moment ou deux pour y penser. Ou plus longtemps ...