Сложная карта с одним ключом типа, но разными значениями типа с использованием C . (Не Multmap)

#c #map

#c #Карта

Вопрос:

Я хочу создать одну карту, подобную этим условиям,

1) Всего 50 строковых ключей. 2) Первые 40 значений являются строками. 3) Остальные 10 значений являются целыми числами.

Нравится

 //No idea how to initialize this map but after initialization
map2D["Key-1"]="Value-1";
map2D["Key-2"]="Value-2";
map2D["Key-3"]="Value-3";
........................
........................
........................
map2D["Key-39"]="Value-39";
map2D["Key-41"]= 123;
map2D["Key-42"]=234;
.......................
.......................
.......................
map2d["Key-50"]=24132;
 

Есть идеи, как достичь этой цели. Спасибо

Комментарии:

1. Создайте объект, содержащий либо строку, либо значение int, и вставьте его в качестве значения.

2. Вы могли бы использовать boost::any в качестве типа значения.

3. @KerrekSB … я хочу сделать это с одной картой и без библиотеки Boost.

Ответ №1:

Вы могли бы использовать вариант класса из библиотеки boost. Думайте об этом как об объединении для типов, отличных от POD.

http://www.boost.org/doc/libs/1_55_0/doc/html/variant.html

Вот пример с веб-страницы:

 std::vector< boost::variant<int, std::string> > vec;
vec.push_back( 21 );
vec.push_back( "hello " );
 

Итак, тип значения вашего контейнера может быть boost::variant<int, std::string> .

Комментарии:

1. Есть идеи без повышения?

Ответ №2:

С технической точки зрения оба решения tgmath верны, но я думаю, вам следует переосмыслить то, чего вы пытаетесь достичь. Какова цель наличия двух разных типов на карте? Как вы на самом деле будете использовать значения?

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

Итак, что вы будете делать со значениями из вашей карты? Если вы будете использовать их в вычислении, вам нужен способ определить, является ли ваше значение строкой или целым числом. Если вы получаете вариант или объединение, вам нужно будет проверить, какое значение действительно представлено перед использованием.

Если вы будете просто выводить значение или другие операции, связанные со строками, с точки зрения дизайна лучше хранить строку. Если вы выполняете операцию, которая должна вести себя по-разному в зависимости от того, используете ли вы строку или целое число, тогда вы можете рассмотреть возможность использования наследования — создайте класс mapValue (используйте более значимое имя), который наследует от него intValue и stringValue . Компилятор будет использовать rtti для правильного поведения.

Объединение будет иметь преимущество в эффективности использования памяти и экономии (обычно незначительных) накладных расходов rtti.

Комментарии:

1. Да. Хороший момент. Это может помочь, если вы учтете это. Также использование двух карт (как предложил @Kerrek_SB) является хорошим моментом.

Ответ №3:

Вот решение без повышения. Используйте объединение и C 11. Это позволяет не-POD-членам. Но будьте осторожны с созданием и удалением строк, чтобы предотвратить утечку памяти.

 union Compound {
    std::string str;
    int i;
    ~Compound() {}
};
 

Работающий пример, как его использовать: http://ideone.com/SUyyv1

Еще одна вещь: обе переменные хранятся в одном блоке памяти. Он может вызвать ошибку segfault для чтения a string , если задан только an int . Вы могли бы исправить это, написав класс с двумя переменными, который знает, содержит ли он a string или an int . Если вы напишете эту версию шаблона, это может оказаться эквивалентом boost::variant.