C++: поиск по карте без использования итератора

Считайте, у меня есть это:

std::map<int, int> intMap;
intMap[11] = 21; 
intMap[12] = 22; 
intMap[13] = 23; 
intMap[14] = 24; 

int val = 0; 

Когда я хочу найти значение map[11], если оно существует, и поместить его в val Я использую:

std::map<int, int>::iterator it = intMap.find(11);
if(it != intMap.end())  
    val = it->second;

Есть ли способ сделать это без использования итератора? Я имею в виду, более короткий путь.

int val = intMap[11] для меня это не вариант, так как он добавляет 11 в качестве ключа для intMap, если его там еще не было, что меня не интересует. см. здесь.

4 ответа

Решение

В с ++11 map имеет новый метод под названием at(Key) который вернет ссылку на сопоставленное значение или выдаст исключение, если Key нет на карте.

В C++ вам понадобится промежуточный итератор.

Андре уже упоминает новый at() функция. В других обстоятельствах может быть полезно следующее:

template <typename Map, typename K, typename T>
T get(Map &map, const K &key, T def) {
    typename Map::const_iterator it = map.find(key);
    return (it == map.end() ? def : it->second);
}

Используйте это как:

int val = get(intMap, 11, 0);

Вы также можете иметь const version с преимуществом возврата ссылки (неконстантная версия возвращает значение, потому что возврат ссылки по умолчанию довольно ограничивающий):

template <typename Map, typename K, typename T>
const T& get(const Map &map, const K &key, const T &def) {
    typename Map::const_iterator it = map.find(key);
    return (it == map.end() ? def : it->second);
}

Просто для забавы, этот код является кратким, но он может потерять для ясности. Он делает то, что вы говорите в комментарии ниже: ничего в том случае, когда 11 нет на карте:

BOOST_FOREACH(const std::pair<int,int> &newval, intMap.equal_range(11)) {
    val = newval.second;
}

Я думаю, это тоже может сработать:

int val;
if (intMap.count(11)) val = intMap[11];

Простая проверка наличия ключа...

Итак, в единственной строке с default_value, как это было предложено Karadoc:

int val = (intMap.count(x) ? intMap[x] : default_value);

Как правило, вам нужно как-то проверить наличие ключа. Однако вы можете написать некоторую функцию, которая выполняет проверку и дает значение, поэтому при вызове вы получите однострочную строку. Вам понадобится некоторое значение по умолчанию для случая, когда ключ не существует на карте. Вот быстрый вывод для этого:

template <class Map, class U>
auto getOrDefault(Map const& m, typename Map::key_type const& key, U&& default_val) 
  -> typename Map::mapped_type
{
  auto pos = m.find(key);
  return pos != m.end() ? pos->second : std::forward<U>(default_val);
}

template <class Map>
auto getOrDefault(Map const& m, typename Map::key_type const& key) 
  -> typename Map::mapped_type
{
  typedef typename Map::mapped_type Value;
  return getOrDefault(m, key, Value{});   
}

//call:
int val = getOrDefault(intMap, 11);       // 0 if key 11 does not exist
int val2 = getOrDefault(intMap, 42, -1);  //-1 if key 42 does not exist

Примечание: мне не удалось дать default_val аргумент по умолчанию - может быть, кто-то может помочь мне с этим. gcc 4.7.2 не смог вывести U когда я пытался с U&& default_val = typename Map::mapped_type{}

Другие вопросы по тегам