C ++ 14: Как я могу использовать мою функцию шаблона с `iterator` и` const_iterator` - PullRequest
1 голос
/ 04 мая 2020

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

template<template <typename...> class Map, typename K, typename T>
bool isEqualToEndOfMap(const typename Map<K, T>::iterator &it, const Map<K, T> &map) {
    return it == map.end();
}

template<template <typename...> class Map, typename K, typename T>
bool isInMap(const K &key, const Map<K, T> &map) {
    return isEqualToEndOfMap(map.find(key), map);
}

Но, к сожалению, map.find() возвращает std::map::const_iterator, что несовместимо с std::map::iterator. Я не могу изменить на const typename Map<K, T>::const_iterator, потому что я хочу использовать isEqualToEndOfMap с обычными итераторами (не константными), из-за этого:

const auto ret = std::find_if(mmap.begin(), mmap.end(),
                                    [streamShm](const std::pair<int, StreamMapContainer> pair) {
                                        return pair.second.pcktRefShm->id() == streamShm->id();
                                    });
if(isEqualToEndOfMap(ret, mmap))

std::find_if возвращает обычный итератор, потому что map.begin() и map.end() возвращаются обычные итераторы. Конечно, кастинг возможен. Но это еще страшнее:

std::map<int, StreamMapContainer>::const_iterator(..).

Ответы [ 2 ]

3 голосов
/ 04 мая 2020

Пара точек:

  1. Для isEqualToEndOfMap нет необходимости принимать итератор по ссылке.
  2. Вы можете использовать const_iterator в качестве типа аргумента в isEqualToEndOfMap. При вызове функции можно использовать объект типа iterator.
template<template <typename...> class Map, typename K, typename T>
bool isEqualToEndOfMap(typename Map<K, T>::const_iterator it, const Map<K, T> &map) {
    return it == map.end();
}

Это должно работать в обоих случаях использования в опубликованном коде.

Обновление в ответ на комментарий ОП.

В комментарии вы написали:

Но даже если это дешево, почему бы не избежать этого?

Вы должны изучить свои варианты и решить, какой из них лучше всего подходит для ваших нужд.

В дополнение к тому, что я уже предложил, я могу вспомнить еще два варианта.

Вариант 2

Есть пара перегрузок, одна для const_iterator и одна для iterator.

template<template <typename...> class Map, typename K, typename T>
bool isEqualToEndOfMap(const typename Map<K, T>::const_iterator &it, const Map<K, T> &map) {
    return it == map.end();
}

template<template <typename...> class Map, typename K, typename T>
bool isEqualToEndOfMap(const typename Map<K, T>::iterator &it, const Map<K, T> &map) {
    return it == map.end();
}

Это не лучше, чем первый вариант, так как вам нужно поддерживать по существу дублированный код.

Опция 3

Использовать const_iterator& в качестве типа аргумента вместо const_iterator.

template<template <typename...> class Map, typename K, typename T>
bool isEqualToEndOfMap(const typename Map<K, T>::const_iterator &it, const Map<K, T> &map) {
    return it == map.end();
}

Это сохраняет вам копию, когда функция вызывается с const_iterator, но все равно требуется копия, временный объект, когда он вызывается с iterator объектом.

Вы могли бы потенциально использовать эту опцию, но это не idiomati c. Объекты-итераторы предназначены для использования почти так, как они считаются указателями и передаются по значению.

Я бы порекомендовал придерживаться первого варианта.

2 голосов
/ 04 мая 2020

Почему бы не два шаблона:

template<template <typename...> class Map, typename K, typename T>
bool isEqualToEndOfMap(const typename Map<K, T>::iterator &it, const Map<K, T> &map) {
    return it == map.end();
}

и:

template<template <typename...> class Map, typename K, typename T>
bool isEqualToEndOfMap(const typename Map<K, T>::const_iterator &it, const Map<K, T> &map) {
    return it == map.end();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...