Votre approche est fondamentalement dans la bonne direction. Vous devez connaître le type dans lequel vous mettez. Vous pouvez utiliser boost::any
et vous serez en mesure de mettre à peu près tout dans la carte, aussi longtemps que vous savez ce que vous mettez dans:
std::map<std::string, boost::any> table;
table["hello"] = 10;
std::cout << boost::any_cast<int>(table["hello"]); // outputs 10
Quelques réponses ont recommandé l'utilisation de boost::variant
pour résoudre ce problème. Mais il ne vous laissera pas stocker des valeurs typées arbitraires dans la carte (comme vous le vouliez). Vous devez connaître l'ensemble des types possibles à l'avance. Étant donné que, vous pouvez le faire ci-dessus plus facilement:
typedef boost::variant<int, std::string, void*> variant_type;
std::map<std::string, variant_type> table;
table["hello"] = 10;
// outputs 10. we don't have to know the type last assigned to the variant
// but the variant keeps track of it internally.
std::cout << table["hello"];
Cela fonctionne parce que boost::variant
operator<<
à cette surcharge fin. Il est important de comprendre que si vous voulez enregistrer ce qui est actuellement contenue dans la variante, vous devez toujours connaître le type, comme dans le boost::any
cas:
typedef boost::variant<int, std::string, void*> variant_type;
std::map<std::string, variant_type> table;
table["hello"] = "bar";
std::string value = boost::get<std::string>(table["hello"]);
L'ordre des affectations à une variante est un moteur d'exécution propriété du flux de contrôle de votre code, mais le type utilisé de n'importe quelle variable est déterminé au moment de la compilation. Donc, si vous voulez obtenir la valeur de la variante, vous devez connaître son type. Une alternative consiste à utiliser les visites, comme indiqué dans la documentation de la variante. Cela fonctionne car la variante stocke un code qui lui indique quel type lui a été assigné en dernier. Sur cette base, il décide lors de l'exécution qui surcharge du visiteur qu'il utilise. boost::variant
est assez grand et ne se conforme pas tout à fait standard, tout en boost::any
est conforme à la norme, mais utilise la mémoire dynamique, même pour les petits types (donc il est variante plus lente. Peut utiliser la pile pour les petits types). Donc, vous devez échanger ce que vous utilisez.
Si vous voulez vraiment mettre des objets dans ce qui ne diffèrent que par la façon dont ils font quelque chose, le polymorphisme est une meilleure façon d'aller. Vous pouvez avoir une classe de base qui vous dérivez de:
std::map< std::string, boost::shared_ptr<Base> > table;
table["hello"] = boost::shared_ptr<Base>(new Apple(...));
table["hello"]->print();
Ce qui serait essentiellement besoin de cette mise en page de classe:
class Base {
public:
virtual ~Base() { }
// derived classes implement this:
virtual void print() = 0;
};
class Apple : public Base {
public:
virtual void print() {
// print us out.
}
};
Le boost::shared_ptr
est un pointeur intelligent que l'on appelle. Il supprimera automatiquement vos objets si vous les supprimez de votre carte et rien d'autre ne les référencera plus. En théorie, vous auriez pu travailler avec un pointeur neutre, mais en utilisant un pointeur intelligent augmentera considérablement la sécurité.Lisez le manuel shared_ptr auquel je suis lié.
BTW, une std :: map n'est pas une table de hachage; il est généralement implémenté comme un arbre rouge-noir, mais dans tous les cas, les clés sont conservées dans l'ordre. Il y a std :: tr1 :: unordered_map, qui est généralement implémenté en tant que table de hachage. –
Chris, merci de l'avoir signalé. Je l'appelle maintenant un "tableau associatif". –
related: ["Quel est le point des tableaux hétérogènes?"] (Http://stackoverflow.com/questions/4534612/what-is-the-point-of-heterogenous-arrays) –