2553. [fund.ts.v2] basic_string_view substring constructor

Section: 7.3 [fund.ts.v2::string.view.cons] Status: NAD Submitter: Evan Teran Opened: 2015-10-29 Last modified: 2018-06-23

Priority: Not Prioritized

View all issues with NAD status.

Discussion:

Addresses: fund.ts.v2

string_view can be tremendously useful for dealing with sub-strings without copying. However, the current proposal for basic_string_view, has no constructor which provides a direct way of creating a view of a sub-string of a basic_string. Instead, we construct a view of the whole basic_string, and then as a second step create a sub-string, for example using substr. To simplify what I believe to be a common use case, I suggest adding an additional constructor.

The proposed wording for this is as follows:

template <class Allocator>
basic_string_view(const basic_string<charT, traits, Allocator>& str, size_type pos, size_type count = npos);

Throws: out_of_range if pos >= str.size().

Effects: Determines the effective length rlen of the string to reference as the smaller of count and size() - pos.

Postcondition:

data_ = str.data() + pos size_ = rlen

In other words, the result is as if constructed via: basic_string_view(basic_string_view(str).substr(pos, count));

An example implementation could look like this:

template <class Allocator>
basic_string_view(const basic_string<charT, traits, Allocator>& str, size_type pos, size_type count = npos) 
  : data_(nullptr), size_(0) 
{
  basic_string_view(str).substr(pos, count).swap(*this);
}

Note that while we have a default parameter for count, pos does not. I believe that it is best to have this as a separate overload, as opposed to default parameters on the current constructor for two reasons:

  1. The current constructor taking a basic_string does not throw, this overload can throw if pos >= str.size().

  2. This constructor performs slightly more work, it is not necessary to impose this extra work on the basic case of constructing a view of a whole string.

This has been briefly discussed in the isocpp forums. There were no obvious objections to this small improvement. Additionally, another reason to consider this addition is to provide a more consistent interface. With raw strings, we have the ability to construct a basic_string_view which is a sub-string. For example:

const char* s = "hello world";
auto v = string_view(s + 6);

But there is no constructor which easily does the same when starting with a basic_string.

Finally, As a example, consider the following (trivial) code:

void print_string(string_view v) {
  std::cout << v << '\n';
}

int main() {
  std::string s = "hello world"; // for example, we want to print the sub-string "world", without copies

  // current method:
  print_substring(string_view(s).substr(6));

  // suggested method:
  print_substring(string_view(s, 6);
}

Previous resolution [SUPERSEDED]:

This wording is relative to N4529.

  1. Insert between 7.3 [fund.ts.v2::string.view.cons] p5 and p6 the following sequence of paragraphs:

    template <class Allocator>
    basic_string_view(const basic_string<charT, traits, Allocator>& str, size_type pos, size_type count = npos);
    

    -?- Throws: out_of_range if pos >= str.size().

    -?- Effects: Determines the effective length rlen of the string to reference as the smaller of count and size() - pos.

    -?- Postcondition: Constructs a basic_string_view, with the postconditions in Table ?

    Table ? — basic_string_view(const basic_string<charT, traits, Allocator>&, size_type, size_type) effects
    Element Value
    data_ str.data() + pos
    size_ rlen

[2016-03, Jacksonville]

Change status to "LEWG"

LEWG: Do we want this constructor?

SF F N A SA

0 3 2 13 1

Proposed resolution:

Not a defect. The LWG believes this missing feature is not sufficiently serious to constitute a defect.