Comment puis-je stocker des objets de types différents dans un conteneur c++?

Y a - t-il un conteneur c++ que je pourrais utiliser ou construire qui peut contenir, par exemple, int et string et double types? Le problème auquel je suis confronté est que chaque fois que j'essaie de remplir, disons, une carte, un vecteur ou une liste avec, disons, ce qui suit:

int x;
string y;
double z;

Je suis limité avec le format:

list<int> mycountainer;
vector<string> mycontainer;

Qui force mycontainer à ne comporter qu'un seul type.

Avant que quelqu'un suggère des génériques, cela ne fonctionnerait pas non plus puisque les conteneurs standard vector et list qui viennent avec C++ sont déjà generic - ils peuvent être des conteneurs pour tous les types mais ne peuvent pas contenir plusieurs types.

Je voudrais éviter D'utiliser Boost aussi si possible - je préférerais s'il y a un moyen simple de coder cela moi-même.

[modifier] Hey guy, merci beaucoup pour vos suggestions - je devrais expliquer comment je vais utiliser ce conteneur, mais c'est un peu compliqué d'où la (grande) simplification ci-dessus. Je pense que la meilleure option ici est d'utiliser le Boost. Encore une fois, merci.

23
demandé sur chema989 2011-01-19 20:14:55

7 réponses

Vous pouvez utiliser (ou ré-implémenter) boost::any et stocker les instances de boost::any dans un récipient. Ce serait le plus sûr, puisque boost::any a probablement traité une grande partie des cas extrêmes et de la complexité impliqués dans la résolution de ce genre de problème dans le cas général.

Si vous voulez faire quelque chose de rapide et sale, créez une structure ou peut-être une union contenant des membres de tous les types potentiels avec une énumération ou un autre indicateur dont le type est 'actif' dans l'objet. Soyez particulièrement prudent avec les syndicats car ils ont des propriétés intéressantes (telles que l'appel d'un comportement indéfini si vous lisez le mauvais membre de l'union, un seul des membres peut être "actif" à la fois, celui qui a été écrit le plus récemment).

Je suis curieux de savoir ce que vous faites que vous avez besoin d'une telle construction, cependant.

19
répondu Josh 2011-01-19 17:21:03

Eh bien, la première question serait: Pourquoi pensez-vous que vous devez stocker des objets de types différents et totalement indépendants dans le même conteneur? Ça me semble louche.

Si j'avais le besoin, je regarderais dans boost::variant ou boost::any.

12
répondu sbi 2011-01-19 17:23:38

Ce que vous voulez est appelé un "conteneur hetrogenious". C++ ne les supporte pas techniquement dans le STL, mais Boost le fait.

Étant Donné que, je pense que vous trouverez votre réponse à la question suivante: comment-ne-vous-faire-un-hétérogène-boostmap

6
répondu T.E.D. 2017-05-23 11:46:14

Vous pouvez utiliser soit des structures, soit des classes ou std:: pair.

[Modifier]

Pour les classes et les structures:

struct XYZ {
    int x;
    string y;
    double z;
};
std::vector<XYZ> container;

XYZ el;
el.x = 10;
el.y = "asd";
el.z = 1.123;
container.push_back(el);

Pour std:: paire:

#include <pair>
typedef std::pair<int, std::pair<string, double> > XYZ;
std::vector<XYZ> container;
container.push_back(std::make_pair(10, std::make_pair("asd", 1111.222)));
2
répondu ssmir 2011-01-19 17:17:52

Vous pouvez utiliser une structure qui contient les trois.

struct Data
{
    int intVal;
    std::string stringVal;
    double doubleVal;
};

Ensuite, vous pouvez simplement déclarer list mycontainer<Data> et utiliser la valeur appropriée, à condition de savoir quel est le type de valeur. Sinon, ajoutez un champ d'addition à la structure qui vous indique lequel des trois types de données est utilisé.

struct Data
{
    enum DATATYPE { DT_INT, DT_STRING, DT_DOUBLE } type;

    int intVal;
    std::string stringVal;
    double doubleVal;
};

Si vous vous inquiétez de l'utilisation de la mémoire, vous pourriez probablement utiliser une union, bien que j'ai tendance à éviter de les utiliser. Cela pourrait être une paranoïa inutile de ma part cependant.

0
répondu James 2011-01-19 17:19:43

Si vous avez un nombre fini d'éléments que vous devez stocker, placez-les dans une classe ou une structure.

S'il n'y a pas de limite aux éléments que vous devez stocker dans ce conteneur, regardez une manière différente de faire les choses car la seule façon de le faire est de les stocker en tant qu'objet, puis de les convertir en leur propre type lorsque vous avez besoin d'y accéder.

Cependant, si un élément peut potentiellement être dans le conteneur, vous n'avez aucun moyen de savoir quel type d'éléments spécifiques dans le conteneur sont, et donc ne sera pas en mesure de les lancer.

Si C++ contenait une réflexion, il y aurait peut-être un moyen de le faire, mais C++ n'a pas de réflexion.

0
répondu jcvandan 2011-01-19 17:23:02

La méthode la plus simple consiste bien sûr à définir une structure ou une classe qui a des membres de chacun des types que vous souhaitez stocker. la réponse de Joshsuggère Boost.Any , qui contiendra à peu près n'importe quoi. Si vous voulez restreindre valeurs à celles de types int, double, et std::string, alors le meilleur choix serait coup de pouce.Variante .

Si vous ne voulez tout simplement pas utiliser Boost, alors je vous suggère de surmonter vos blocages et de l'utiliser de toute façon. "Pas inventé ici" est une politique autodestructrice. Mais si vous ne pouvez pas utiliser Boost, vous pouvez écrire votre propre classe variant à la place. Andrei Alexandrescu a écrit une série en trois parties sur cette partie (1, Partie 2, partie 3 ) Il y a quelques années, et sa conception a inspiré L'un Boost utilise.

0
répondu Rob Kennedy 2017-05-23 12:32:02