При наличии итератора, возможно ли получить / использовать правильную функцию сравнения для коллекции, на которую ссылается этот итератор?
Например, давайте предположим, что я пишу общий алгоритм:
template <class InIt, class T>
void do_something(InIt b, InIt e, T v) {
// ...
}
Теперь, скажем, я хочу сделать что-то простое, как найти v
в [b..e)
, Если b
а также e
итераторы над std::vector
Я могу просто использовать if (*b == v) ...
, Предположим, однако, что b
а также e
итераторы над std::map
, В этом случае я должен только сравнить ключи, не весь тип значения того, что содержится в карте.
Таким образом, вопрос в том, что, учитывая эти итераторы в карте, как мне извлечь функцию сравнения этой карты, которая будет сравнивать только ключи? В то же время я не хочу слепо предполагать, что я работаю с map
или. Например, если итераторы указали на set
Я хотел бы использовать функцию сравнения, определенную для этого set
, Если они указали на vector
или же deque
Я бы, наверное, должен использовать ==
потому что в этих контейнерах не будет определена функция сравнения.
О, почти забыл: я понимаю, что во многих случаях контейнер будет иметь только эквивалент operator<
скорее, чем operator==
для элементов, которые он содержит — я прекрасно справляюсь с возможностью использовать это.
Не существует стандартного способа сопоставления итератора с базовым типом контейнера (если такой контейнер вообще существует). Вы можете использовать некоторую эвристику, чтобы попытаться определить, какой контейнер, хотя это не будет простым и, вероятно, также не гарантировано.
Например, вы можете использовать метафункцию, чтобы определить, является ли * value_type * std::pair<const K, T>
что намекает на то, что это может быть std::map
и после извлечения типов K
а также T
попытаться использовать метафункцию, чтобы определить, является ли тип итератора и тип std::map<K,T,X,Y>::iterator
или же std::map<K,T,X,Y>::const_iterator
соответствовать определенной комбинации X
, Y
,
В случае карты этого может быть достаточно для определить (то есть с большой вероятностью успеха), что итератор ссылается на std::map
, но вы должны заметить, что даже если вы можете использовать это и даже извлечь тип X
компаратора, этого недостаточно для копировать компаратор в общем случае. В то время как необычные (и не рекомендуемые) компараторы могут иметь состояние, и вы не знаете, каким является конкретное состояние компаратора, не имея прямого доступа к контейнеру. Также обратите внимание, что есть случаи, когда этот тип эвристики даже не поможет, в некоторых реализациях std::vector<>
тип итератора является непосредственно указателем, и в этом случае вы не можете различить «итератор» в массив и итератор в std::vector<>
из тех же основных типов.
Итераторы не должны быть связаны с контейнерами, поэтому они не дают вам никакой информации о контейнерах, с которыми они не обязательно связаны. Это основная абстракция итератора: итераторы разграничивают последовательности, независимо от того, откуда эта последовательность. Если вам нужно знать о контейнерах, вы должны написать алгоритмы, которые принимают контейнеры.
К сожалению, итераторы не всегда знают о контейнере, который их содержит (а иногда они вообще не находятся в стандартном контейнере). Даже iterator_traits
есть только информация о типе value_type, которая конкретно не говорит вам, как сравнивать.
Вместо этого давайте черпать вдохновение из стандартной библиотеки. Все ассоциативные контейнеры (map
и т. д.) имеют свои find
методы, а не с помощью std::find
, И если вы делать нужно использовать std::find
на таком контейнере вы не: вы используете find_if
,
Похоже, ваше решение заключается в том, что для ассоциативных контейнеров вам нужен do_something_if
который принимает предикат, говорящий ему, как сравнивать записи.