Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructing a string_view from a range of chars

While a span can be constructed from a range, a string_view cannot be constructed from a range of chars.

Thus, for example, the following code is required:

// assume chars_span is a span of chars
std::cout << std::string_view(chars_span.data(), chars_span.size());
// or:
std::cout << std::string_view(chars_span.begin(), chars_span.end());

Instead of a simpler range-syntax that is not supported:

std::cout << std::string_view(chars_span);

Is there a reason for not having a constructor for string_view that accepts a range of chars, or was it just overlooked or not considered important enough?

like image 853
Amir Kirsh Avatar asked Oct 06 '20 15:10

Amir Kirsh


People also ask

Can you modify a string_view?

Unlike other string types, you should pass string_view by value just like you would an int or a double because string_view is a small value. Marking a string_view as const only affects whether the string_view object itself can be modified, and not whether it can be used to modify the underlying chars – it never can.

What is a string view?

What is string_view ? Conceptually, string_view is only a view of the string and cannot​ be used to modify the actual string. When a string_view is created, there's no need to copy the data (unlike when you create a copy of a string). Furthermore, in terms of size on the heap, string_view is smaller than std::string .

Should I pass string_view by reference?

So, frequently, you can pass string_view by reference and get away with it. But you should pass string_view by value, so that the compiler doesn't have to do those heroics on your behalf. And so that your code-reviewer doesn't have to burn brain cells pondering your unidiomatic decision to pass by reference.

Is string_view a pointer?

Typically, a std::string_view object contains a pointer to constant char and a size members. The pointer points to the beginning of the array, and the size has its length.


1 Answers

P1391r3 proposed this, though this was dropped in the version that was eventually adopted for C++20: P1391r4. The reason for the drop unfortunately is completely absent from the paper (indeed, the paper does not even mentioned that it was dropped).

However, a follow-up paper, P1989R0 presents the issue as what happens if we had a type like this (I modified the example slightly):

struct buffer {
    buffer() {};
    char const* begin() const { return data; }
    char const* end() const { return data + 42; }
    operator string_view() const {
        return string_view(data, data + 2);
    }
private:
    char data[42];
};

Here, buffer is convertible to string_view. But the way in which it is convertible to string_view differs in the way in which string_view's range constructor would do it (the former gives you two chars, the latter gives you 42). As far as I am aware, nobody has actually pointed out the existence of such types.

Nevertheless, the direction was to ensure that those types continue to just work, so the new paper has a more complicated set of constraints for that particular constructor.


A more interesting example would be something like:

using ci_string = std::basic_string<char, case_insensitive_traits>;

ci_string value = "Hello";
std::string_view sv = value;

Any kind of straightforward range-based reasoning would allow the conversion from ci_string to std::string. A ci_string is a perfectly good contiguous range of char, without any weird conversion issues like the buffer type from earlier. But while ci_string should be convertible to basic_string_view<char, case_insensitive_traits>, we probably wouldn't want to avoid it being convertible to just normal string_view. That's unlikely to be intended, so it's something that we need to try to guard against.

This case is much more motivating for me than the buffer case.

like image 64
Barry Avatar answered Nov 15 '22 06:11

Barry