Поиск в зависимости от аргумента забавная старая вещь, не правда ли?
Уже существует operator<
, относящийся к std::string
в пространстве имен std
, и это обнаруживается при поиске <
, который соответствует вашим аргументам. Возможно, нелогично (но не без веской причины), , дальнейший поиск не предпринимается после этого! Другие пространства имен не ищутся. Это даже при том, что только ваша перегрузка фактически соответствует обоим аргументам. Ваш глобальный operator<
эффективно скрыт в этом контексте, как показано в следующем ужасающем примере:
namespace N
{
struct Foo {};
bool operator<(Foo, Foo) { return false; }
}
bool operator<(N::Foo, int) { return false; }
namespace N
{
template <typename T1, typename T2>
bool less(T1 lhs, T2 rhs)
{
return lhs < rhs;
}
}
int main()
{
N::Foo f;
N::less(f, 3);
}
/*
main.cpp: In instantiation of 'bool N::less(T1, T2) [with T1 = N::Foo; T2 = int]':
main.cpp:22:17: required from here
main.cpp:15:20: error: no match for 'operator<' (operand types are 'N::Foo' and 'int')
return lhs < rhs;
~~~~^~~~~
*/
Теперь вы не можете добавлять вещи в пространство имен std
, но это хорошо, потому что было бы намного лучше , если бы вы не перегружали операторы, относящиеся к типам других людей, в любом случае. Это самый быстрый способ скрыть ошибки ODR, когда какая-то другая библиотека делает то же самое.
Точно так же создание чего-то, называемого Key
, то есть на самом деле просто скрытого std::string
, - это рецепт непреднамеренных конфликтов и неожиданного поведения.
В целом, я бы настоятельно рекомендовал сделать ваш Key
как минимум "сильным псевдонимом" для std::string
; то есть его собственный тип, а не просто псевдоним. Как вы узнали, это также решает вашу проблему, потому что теперь operator<
и тип операнда находятся в одном пространстве имен.
В целом, если вы не действительно используете псевдоним здесь, но действительно хотите работать со стандартными типами, вы вернулись к написанию именованного пользовательского компаратора, который очень хорошо изолирует новую логику и также довольно прост в использовании. Недостатком, конечно, является то, что вы должны каждый раз подписываться на него, но я думаю, что в целом это того стоит.