Причина такого сравнения не может быть неоднозначной в том, что ни std::string
, ни std::string_view
не являются простыми типами. Вместо этого это экземпляры шаблонов классов и соответствующие операторы сравнения:
template <class charT, class traits, class alloc>
constexpr bool operator==(const basic_string<charT, traits, alloc>& lhs,
const basic_string<charT, traits, alloc>& rhs) noexcept;
template <class charT, class traits>
constexpr bool operator==(basic_string_view<charT, traits> lhs,
basic_string_view<charT, traits> rhs) noexcept;
Такие шаблоны определенных функций не учитывают никаких преобразований. Вместо этого они ожидают, что операнды будут иметь точно такой же тип, поскольку только тогда успешное вычитание (те же типы могут быть выведены для параметров шаблона левого и правого операндов), создавая жизнеспособного кандидата. Точно так же:
template <typename T>
void foo(T, T);
foo(42, 'x'); // error
терпит неудачу из-за несоответствия типов аргументов, поскольку T
не может быть либо int
, либо char
, хотя преобразования между ними существуют. Кроме того:
struct my_string
{
operator std::string() const { return ""; }
};
std::string s;
my_string ms;
s == ms; // error
терпит неудачу, потому что компилятор не может вывести basic_string<charT, traits, alloc>
из my_string
, хотя существует неявное преобразование в его экземпляр.
Сравнение s1 == s2
, однако, работает, поскольку ожидается, что реализация стандартной библиотеки обеспечит перегрузки, которые могут учитывать неявные преобразования из любого типа в std::basic_string_view
(такое неявное преобразование существует из std::string
в std::string_view
). Это может быть достигнуто, например, путем запрета вычета для одного из параметров, как показано в части примера [string.view.comparison] / p1 :
template <class charT, class traits>
constexpr bool operator==(basic_string_view<charT, traits> lhs,
__identity<basic_string_view<charT, traits>> rhs) noexcept;
Помещая тип одного из операндов в __identity
, определенный как template <class T> using __identity = decay_t<T>;
, он вводит невыгружаемый контекст , создавая перегрузку для некоторого std::basic_string_view
и другого аргумента, неявно преобразуемого в тот же экземпляр шаблона класса std::basic_string_view
.