Получить функцию сравнения контейнера с помощью итератора - программирование

Получить функцию сравнения контейнера с помощью итератора

Учитывая итератор, можно ли получить/использовать правильную функцию сравнения для коллекции, к которой относится этот итератор?

Например, допустим, что я пишу общий алгоритм:

template <class InIt, class T>
void do_something(InIt b, InIt e, T v) { 
    // ...
}

Теперь скажем, я хочу сделать что-то простое, например find v в [b..e). Если b и e являются итераторами над std::vector, я могу просто использовать if (*b == v) .... Предположим, однако, что b и e являются итераторами над a std::map. В этом случае я должен сравнивать только ключи, а не весь тип значения того, что содержится на карте.

Итак, вопрос в том, что, учитывая эти итераторы на карте, как мне получить эту функцию сопоставления карт, которая будет сравнивать только ключи? В то же время я не хочу слепо предположить, что я работаю с map. Например, если итераторы указали на set, я бы хотел использовать функцию сравнения, определенную для этого set. Если они указали на vector или deque, мне, вероятно, придется использовать ==, потому что в этих контейнерах не будет определена функция сравнения.

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

4b9b3361

Ответ 1

Нет стандартного способа сопоставления от итератора к базовому типу контейнера (если таковой вообще существует). Возможно, вы сможете использовать некоторые эвристики, чтобы попытаться определить, какой контейнер, хотя это будет не просто и, вероятно, не гарантируется.

Например, вы можете использовать metafunction, чтобы определить, является ли значение * value_type * std::pair<const K, T>, что является подсказкой, что это может быть std::map, и после извлечения типов K и T попытайтесь использовать metafunction, чтобы определить, подходит ли тип итератора и тип std::map<K,T,X,Y>::iterator или std::map<K,T,X,Y>::const_iterator для конкретной комбинации X, Y.

В случае карты, которая может быть достаточной для определения (т.е. угадывания с высокой вероятностью успеха), что итератор ссылается на std::map, но вы должны заметить, что даже если вы можете использовать это и даже извлечь тип X компаратора, что недостаточно для репликации компаратора в общем случае. В то время как необычные (и не рекомендуемые) компараторы могут иметь состояние, и вы не знаете, какое именно состояние компаратора не имеет прямого доступа к контейнеру. Также обратите внимание, что есть случаи, когда этот тип эвристики даже не поможет, в некоторых реализациях std::vector<> тип итератора является прямым указателем, и в этом случае вы не можете различать "итератор" в массив и итератор в std::vector<> того же базового типа.

Ответ 2

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

Ответ 3

К сожалению, итераторы не всегда знают о контейнере, который их содержит (а иногда они вообще не находятся в стандартном контейнере). Даже iterator_traits имеет только информацию о значении value_type, который конкретно не говорит вам, как сравнивать.

Вместо этого дайте вдохновение из стандартной библиотеки. Все ассоциативные контейнеры (map и т.д.) Имеют свои собственные методы find вместо использования std::find. И если вам нужно использовать std::find в таком контейнере, вы не используете: find_if.

Похоже, ваше решение состоит в том, что для ассоциативных контейнеров вам нужен do_something_if, который принимает предикат, сообщающий ему, как сравнивать записи.