Constructing a string_view from a range of chars

1.7k views Asked by At

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?

1

There are 1 answers

3
Barry On BEST ANSWER

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.