Сравнение std::string_view и подстроки string_view

Допустим, у нас есть string_view и еще одно string_view, которое является подмножеством первого string_view:

using namespace std; // just to shorten the example...

string_view s{"abc def"};
auto t = s.substr(4);
auto u = s.substr(0, 4);

cout << *(s.begin() + 4) << "  " << *t.begin() << '\n';
cout << ((s.begin() + 4) == t.begin());
cout << (s.end() == t.end());
cout << ((s.begin() +5) == t.begin());
cout << ((s.begin() +5) == (t.begin() + 1));
cout << ((s.begin() + 4) == u.end()); // true

Все сравнения будут работать в Linux с gcc (9 HEAD) и clang (8 HEAD). В Windows Visual c++ (15.7.6) сравнение двух итераторов не разрешено (в режиме отладки вы получаете ошибку утверждения cannot compare incompatible string_view iterators for equality).

Далее идет сравнение указателей:

string_view s{"abc def"};
char const*& it{...}; // contains pointer to some location in s
auto t = s.substr(4);

it == s.end(); // works in gcc/clang - fails to compile in Visual studio

Поэтому, когда вы пытаетесь исправить это в Visual C++, вы хотите сравнить адреса it == &*s.end(), но это не удается, поскольку итератор end() не должен разыменовываться (UB, если я правильно помню), поэтому вы получаете cannot dereference end string_view iterator.

boost::string_view поддерживает сравнение it == s.end(), поэтому я удивлен, что реализация std более ограничена (и, следовательно, гораздо менее удобна для кросс-платформенной работы)

Я понимаю, что сравнение итераторов двух разных контейнеров - это UB, но string_view не является контейнером (у него нет базовой памяти), это некоторая форма интеллектуального указателя, поэтому я ожидаю, что язык позволит мне сравнивать такие итераторы, доверяя мне, что представления указывают на другое (или одно и то же) подмножество одного и того же контейнера.

Итак, мой вопрос: как я могу заставить что-то подобное работать только с string_view?

(Это означает, что нет необходимости создавать собственный класс диапазона, который будет содержать два итератора, поскольку это в первую очередь противоречит цели использования std::string_view)


person Domen Vrankar    schedule 23.09.2018    source источник
comment
Каков ваш вариант использования? Я не вижу причин делать то, что вы хотите делать с string_views?   -  person NoSenseEtAl    schedule 23.09.2018
comment
@NoSenseEtAl Я изменяю boost::beast, чтобы использовать его с std::string_view вместо boost::string_view с минимальными изменениями (см. класс const_iterator basic_parsed_list: github.com/boostorg/beast/blob/develop/include/boost/beast/http/). В Linux это все, что нужно: github.com/boostorg/beast/pull/1241 а в винде немного больше работы...   -  person Domen Vrankar    schedule 24.09.2018
comment
@Justin, это часть it == s.end(), где изменение его на it == &*s.end() вызывает ошибку подтверждения во время выполнения, что конечный итератор не следует разыменовывать (для остальных указателей между begin и end-1, которые будут работать).   -  person Domen Vrankar    schedule 24.09.2018


Ответы (1)


Похоже, вы хотите работать с необработанными указателями.

Если вы хотите работать с необработанными указателями, используйте .data() вместо .begin() и .data()+.size() вместо end().

Эти указатели ведут себя так, как вы хотите, чтобы вели себя итераторы строкового представления.

Если вам нужны итераторы обратно, ptr-.data()+.begin() восстанавливает итератор (и it-begin()+.data() выполняет возврат к ptr).

person Yakk - Adam Nevraumont    schedule 24.09.2018