Problem: I want disparate sections of my code to have access to a common collection that stores objects of different types in such a way that the type of each object is known and, to a decisive extent, retrieving from the collection should check the type at compile time. (I understand that this is close to the question asked earlier, but please read, this is somewhat more specific.)
To give a concrete example, I would like to do something as follows:
// Stuff that can go in the collection: enum Key { NUM_APPLES /* (unsigned int) */, APPLE_SIZE /* (double) */ } map<Key, Something> collection; unsigned int * nApples = collection.find(NUM_APPLES); int * appleSize = collection.find(APPLE_SIZE); // COMPILATION ERROR - WRONG TYPE
My solution: So far, I have developed the following solution using boost::any :
Key:
using namespace std; using namespace boost::any; struct KeySupertype { protected: // Can't create an instance of this type KeySupertype() {} private: // Can't copy KeySupertype& operator = (const KeySupertype& other) {} KeySupertype(const KeySupertype& other) {} }; template <typename Type> struct Key : public KeySupertype { public: Key() {} };
Collection:
class PropertiesMap { public: template<typename T> T * find(Key<T> & key); private: map<const KeySupertype *, any> myAnyMap; }; template <typename T> T * PropertiesMap::find(Key<T> & key) { const map<const KeySupertype *, any>::iterator it = myAnyMap.find(&key); if(it == myAnyMap.end()) return NULL; return any_cast<T>(&it->second); }
Using:
static const Key<unsigned int> NUM_APPLES; static const Key<double> APPLE_SIZE; PropertiesMap collection; unsigned int * const nApples = collection.find(NUM_APPLES); int * const nApples = collection.find(NUM_APPLES);
This type of type information is encoded with each Key in accordance with its template parameter, so the type will be used when interacting with the collection.
Questions:
1) Is this a reasonable way to achieve my goal?
2) The nasty point is that the collection uses the address of Key objects as an internal std::map key. Is there any way around this? Or at least a way to mitigate abuse? I tried to use a unique int in each key that was generated from static int (and does type std::map type int ), but I would like to avoid statics, if possible, to explain the flows.
3) To avoid using boost::any , would it be wise to have a type std::map type <const KeySupertype *, void *> and use static_cast<T> instead of any_cast ?