std :: map готовят, но не вставляют - PullRequest
2 голосов
/ 17 ноября 2011

У меня есть std: карта, определенная следующим образом:

std:map<std::string country, std::vector<SomeClass> events>; 

Содержит некоторые события, которые произойдут в некоторых странах мира.

Я хочу, чтобы моя основная функция создала эту карту с именем ключа, но без вставки значения. Допустим, ключом является название страны. Я хочу создать «позицию» «США», не вставляя событие, которое произойдет в будущем.

Моя функция события () будет вводить новое, даже не проверяя, является ли ключ действительным

Возможно ли это? Как-нибудь ввести value_pair с «пустым» значением?

ОБНОВЛЕНИЕ: без повышения ...

Ответы [ 4 ]

4 голосов
/ 17 ноября 2011

Будет ли вставка пустой vector добиваться цели? ...

events.insert(std::make_pair("USA", std::vector<SomeClass>()));

Затем вы можете добавить фактические события, не проверяя наличие значения карты:

void event(const std::string& country, const SomeClass& data) {
    events[country].push_back(data);
}

Я не уверен, что это то, что вы ищете, поскольку понятие «создание» позиции «США» выглядит неоднозначно. (И более ранние ответы, кажется, выбирают его по-разному).

EDIT : Как указали комментаторы, вставка пустого вектора даже не требуется, поскольку значения карты создаются автоматически (с использованием инициализатора по умолчанию) и вставляются, когда используется оператор []. Следовательно, вы можете просто сделать events["USA"].push_back(data) напрямую.

2 голосов
/ 17 ноября 2011

Ваш вопрос несколько неясен.Вы не можете вставить ключ без вставки значения.Если это действительно ваше намерение, ответ: Нет.

. Для вашей цели я не вижу причин, по которым вы не могли бы вместо этого вставить пустой вектор (как отмечали другие).Для этого вы можете выполнить вставку при инициализации карты:

#include <string>
#include <map>
#include <initializer_list>
using namespace std;

class SomeClass { int x; };

int main() {
  SomeClass e1, e2, e3;
  map< string, vector<SomeClass> > events = // using initializer_list from c++0x  
  {
    {"USA",{e1,e2}}, {"CANADA",{ /* no events */ }, {"MEXICO",{e2,e3}}
  };
  // or later ...
  events["CUBA"] = {};
  events["RUSSIA"] = {e1,e2,e3};
}

В качестве альтернативы, вы можете вернуть значение по умолчанию, если ключ отсутствует, когда вы его запрашиваете, то есть lazyинициализация .Поведение map по умолчанию заключается в добавлении новой записи на карту с использованием конструктора по умолчанию типа значения всякий раз, когда запрашиваемый ключ отсутствует.Который выдает пустой vector<SomeClass> в этом случае.Поэтому я не вижу, что не так с этим:

events["key that is missing beforehand"].push_back(e1);

Если вы действительно хотите избежать добавления новых записей на карту, вам нужно обернуть свои запросы чем-то вроде:

string key = "USA";
vector<SomeClass> localEvents; // default, empty vector
// using the auto type from c++0x
auto ev = events.find(key);
if (ev == events.end()) // not found
  //events[key] = {}; // don't add the key to the map
  ;
else // get the corresponding vector
  localEvents = (*ev).second;

Для этого вы можете также рассмотреть вопрос, связанный с этим: std :: map значение по умолчанию

(примеры отлично бы работали даже без c++0x возможностей.)

2 голосов
/ 17 ноября 2011

Я думаю, что вы ищете std :: multimap .Это позволяет использовать более одного значения для каждого ключа:

typedef std::multimap<std::string, SomeClass> EventMap;
typedef EventMap::value_type EntryType; // std::pair<..>

std::multimap<std::string, SomeClass> events;
// Add value
events.insert(std::make_pair("Norway", SomeClass(...)));

Если вам действительно нужно пометить страну как действительную, вставив пустой заполнитель, я думаю, что использование отдельного std::set, вероятно, было бы лучшим решением.,Если вы действительно хотите это сделать, boost::optional или shared_ptr, как упомянуто sehe, является другим решением.

1 голос
/ 17 ноября 2011

Идиоматическое решение (я) было бы

typedef std::shared_ptr<SomeClass> element_t;
std::map<std::string, std::vector<element_t> >; 

Или

typedef boost::optional<SomeClass> element_t;
std::map<std::string, std::vector<element_t> > map; 

Тогда вы могли бы получить его и использовать так:

if (map["USA"])
{
     SomeClass& use = *map["USA"];
     // ...
}
...