Проблема: Я хочу, чтобы разрозненные разделы моего кода имели доступ к общей коллекции, в которой хранятся объекты разных типов, таким образом, чтобы тип каждого объекта был известен, и, что особенно важно, был получен из коллекция должна проверяться типом во время компиляции. (Я понимаю, что это близко к вопросам, заданным ранее, но, пожалуйста, продолжайте читать, это несколько конкретнее.)
Чтобы привести конкретный пример, я хотел бы что-то, что делает следующее:
// 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
Мое решение: До сих пор я разработал следующее решение, используя boost::any
:
Ключ:
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() {}
};
Коллекция:
class PropertiesMap
{
public:
template<typename T>
T * find(Key<T> & key);
/* Skipping erase, insert and other methods for brevity. */
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);
}
Использование:
static const Key<unsigned int> NUM_APPLES;
static const Key<double> APPLE_SIZE;
PropertiesMap collection;
/* ...insert num apples and apple size into collection ...*/
unsigned int * const nApples = collection.find(NUM_APPLES);
int * const nApples = collection.find(NUM_APPLES); // COMPILATION ERROR
Таким образом, информация о типе кодируется с каждым Key
в соответствии с его параметром шаблона, поэтому тип будет принудительно применяться при взаимодействии с коллекцией.
Вопросы:
1) Это разумный способ достичь моей цели?
2) Суть в том, что коллекция использует адрес объектов Key
в качестве внутреннего ключа std::map
. Это можно обойти? Или, по крайней мере, способ уменьшить злоупотребление? Я пытался использовать уникальный int
в каждом ключе, который был сгенерирован из static int
(и делал тип ключа std::map
int
), но я хотел бы избежать статики, если это возможно по причинам многопоточности.
3) Чтобы избежать использования boost::any
, было бы разумно иметь std::map
типа <const KeySupertype *, void *>
и использовать static_cast<T>
вместо any_cast
?