0

Let's say that we have a string_view and another string_view that is a subset of the first 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

All the comparisons would work on Linux under gcc (9 HEAD) and clang (8 HEAD). Under Windows Visual c++ (15.7.6) the comparison of two iterators is not allowed (in debug mode you get an assert error cannot compare incompatible string_view iterators for equality).

Next is pointer comparison:

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

So when you try to fix it in Visual C++ you want to compare addresses it == &*s.end() but this fails as end() iterator is not supposed to be dereferenced (UB if I remember correctly) so you get cannot dereference end string_view iterator.

boost::string_view supports it == s.end() comparison so I'm surprised that the std implementation is more limiting (and thereby far less user friendly for cross platform work)

I understand that iterator comparison of two different containers is UB but string_view is not a container (it doesn't own underlying memory) it's some form of a smart pointer so I would expect the language to allow me to compare such iterators trusting me that the views are pointing to a different (or same) subset of the same container.

So my question is how can I make something like this work with string_view only?

(Meaning without needing to create a custom range class that will contain two iterators as this would defeat the purpose of using std::string_view in the first place)

Domen Vrankar
  • 1,743
  • 15
  • 19
  • 1
    What is your use case? I see no reason to do what you want to do with string_views? – NoSenseEtAl Sep 23 '18 at 20:49
  • @NoSenseEtAl I'm modifying boost::beast to use it with std::string_view instead of boost::string_view with as little changes as possible (see basic_parsed_list const_iterator class: https://github.com/boostorg/beast/blob/develop/include/boost/beast/http/detail/basic_parsed_list.hpp). On Linux this is all it takes: https://github.com/boostorg/beast/pull/1241 and on Windows it's a bit more work... – Domen Vrankar Sep 23 '18 at 21:46
  • 1
    @Justin that's the `it == s.end()` part where changing it to `it == &*s.end()` triggers a runtime assert error that end iterator should not be dereferenced (for the rest of the pointers between begin and end-1 that would work). – Domen Vrankar Sep 23 '18 at 22:11

1 Answers1

5

You appear to want to work with raw pointers.

If you want to work with raw pointers, use .data() instead of .begin() and .data()+.size() instead of end().

These pointers behave like you want string view iterators to behave.

If you need iterators back, ptr-.data()+.begin() reconstructs an iterator (and it-begin()+.data() round trips back to ptr).

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524