operator==
неизбежно для std::map::find()
Это то место, где вы ошибаетесь. map
вообще не использует operator==
, это не «неизбежно». Две клавиши x
и y
считаются эквивалентными для целей карты, если !(x < y) && !(y < x)
.
map
не знает или не заботится, внедрили ли вы operator==
. Даже если это так, не обязательно, чтобы все эквивалентные ключи в заказе были равны согласно operator==
.
Причина всего этого заключается в том, что везде, где С ++ опирается на порядки (сортировка, карты, множества, бинарный поиск), он основывает все, что он делает, на хорошо понятой математической концепции «строгого слабого порядка», которая также определяется в стандарте. Нет особой необходимости в operator==
, и если вы посмотрите на код для этих стандартных функций, вы не очень часто будете видеть что-то вроде if (!(x < y) && !(y < x))
, которое выполняет оба теста близко друг к другу.
Кроме того, все это не обязательно основано на operator<
. Компаратором по умолчанию для map
является std::less<KeyType>
, который по умолчанию использует operator<
. Но если вы специализировали std::less
для KeyType
, вам не нужно определять operator<
, и если вы указываете другой компаратор для карты, то он может иметь или не иметь никакого отношения к operator<
или std::less<KeyType>
. Итак, где я сказал x < y
выше, на самом деле это cmp(x,y)
, где cmp
- строгий слабый порядок.
Эта гибкость - еще одна причина, почему бы не перетащить operator==
в нее. Предположим, что KeyType
равно std::string
, и вы указываете свой собственный компаратор, который реализует какие-то правила сортировки, не зависящие от локали, без учета регистра. Если map
использовал operator==
некоторое время, то это полностью игнорировало бы тот факт, что строки, отличающиеся только регистром, должны считаться одним и тем же ключом (или в некоторых языках: с другими различиями, которые считаются несущественными для целей сопоставления). ). Таким образом, сравнение на равенство также должно быть настраиваемым, но будет только один «правильный» ответ, который может дать программист. Это не очень хорошая ситуация, вы никогда не хотите, чтобы ваш API предлагал что-то похожее на настройку, но на самом деле это не так.
Кроме того, концепция заключается в том, что, как только вы исключили участок дерева, который меньше, чем ключ, который вы ищете, и участок дерева, для которого ключ меньше, чем он, то остается либо пусто (совпадение не найдено) или есть ключ (совпадение найдено). Итак, вы уже использовали current < key
, а затем key < current
, не оставляя другого выбора, кроме эквивалентности. Ситуация точно:
if (search_key < current_element)
go_left();
else if (current_element < search_key)
go_right();
else
declare_equivalent();
и вы предлагаете:
if (search_key < current_element)
go_left();
else if (current_element < search_key)
go_right();
else if (current_element == search_key)
declare_equivalent();
что явно не нужно. На самом деле, это ваше предложение, которое менее эффективно!