c ++ 17 Неоднозначность при сравнении string_view со строкой - PullRequest
0 голосов
/ 12 сентября 2018

Я видел, что и string_view, и string имеют симметричный оператор ==, а для строки он имеет конструктор для принятия string_view и оператор для преобразования себя в string_view. Поэтому, когда мы пытаемся использовать оператор == сравнивать между string_view и string, это должно быть неоднозначно?

Я думаю, что-то не так с моими мыслями. Пожалуйста, дайте мне знать, спасибо заранее!

пример:

std::string s1 = "123";
std::string_view s2 = "123";
// in the following comparison, will s1 use the convert operator to generate a string_view, or will s2 use string's string_view constructor to generate a string?
if (s1 == s2) {...}

Ответы [ 2 ]

0 голосов
/ 12 сентября 2018

Это работает из-за нечетного предложения в [string.view.comparisons] :

Пусть S будет basic_­string_­view<charT, traits>, а sv будет экземпляромS.Реализации должны обеспечивать достаточные дополнительные перегрузки, помеченные constexpr и noexcept, чтобы можно было сравнить объект t с неявным преобразованием в S в соответствии с таблицей 62. Списки

и Таблица 62все операторы сравнения с видом по обе стороны выражения.

Поскольку std::string имеет неявное преобразование в std::string_view, именно эта перегрузка будет выбрана.Такие перегрузки будут точно соответствовать случаю s1 == s2, поэтому неявные преобразования не будут учитываться.

По сути, это реализуется с помощью инструментов SFINAE.Примерно так:

template<typename Str>
std::enable_if_t<std::is_convertible_v<std::string_view, Str>, bool> operator==(const Str &rhs, const std::string_view &lhs);

Такая перегрузка не требует неявных преобразований, поэтому она лучше, чем любая перегрузка, которая делает.

0 голосов
/ 12 сентября 2018

Причина такого сравнения не может быть неоднозначной в том, что ни 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.

...