C ++ хранит несколько типов данных в одной коллекции - PullRequest
4 голосов
/ 19 марта 2012

Проблема: Я хочу, чтобы разрозненные разделы моего кода имели доступ к общей коллекции, в которой хранятся объекты разных типов, таким образом, чтобы тип каждого объекта был известен, и, что особенно важно, был получен из коллекция должна проверяться типом во время компиляции. (Я понимаю, что это близко к вопросам, заданным ранее, но, пожалуйста, продолжайте читать, это несколько конкретнее.)

Чтобы привести конкретный пример, я хотел бы что-то, что делает следующее:

// 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?

1 Ответ

0 голосов
/ 20 марта 2012

1) Хорошо выглядит, умное решение

2) Думаю, вы боитесь, что кто-то скопирует ключ и его адрес изменится.Если это ваша проблема, оставьте поле "оригинальный адрес" в вашем KeySuperType.Во время построения установите исходный адрес для этого, во время копирования установите исходный адрес для исходного адреса правой руки (источника).Используйте этот оригинальный адрес для доступа к содержимому карты.Я действительно не мог придумать решение во время компиляции, поскольку во время компиляции модули компиляции не будут знать друг о друге.Вы можете назначить уникальные идентификаторы ключам как можно раньше во время соединения, и получение адреса глобальных переменных своего рода эквивалентно этому.Единственное слабое место, которое я вижу в этом решении, - если вы определите один и тот же ключ в двух динамических общих библиотеках без extern, у них будут молча иметь свои версии ключа с разными адресами.Конечно, если все идет в один и тот же двоичный файл, у вас не возникнет этой проблемы, поскольку два объявления без extern приведут к ошибке компоновщика «Multiple объявлений».

3) Если ваша проблема с boost::any зависит от наддува (что более приемлемо, чем вы думаете), затем реализуйте any самостоятельно, это удивительно просто.Если проблема заключается в производительности, то static_cast<> мне тоже кажется нормальным, если вы держите внутренние органы вашего PropertiesMap подальше от тех, кто не знает, что делает ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...