简体   繁体   中英

Why can't I create a std::string_view from std::string iterators?

It is possible to create a std::string_view from a std::string easily. But if I want to create a string view of a range of std::string using the iterators of the std::string does not work.

Here is the code that I tried: https://gcc.godbolt.org/z/xrodd8PMq

#include <iostream>
#include <string>
#include <string_view>
#include <iterator>

int main()
{
    std::string str{"My String"};
    std::string_view strView{str};  // works
    //std::string_view strSubView{str.begin(), str.begin() + 2}; // error
}

Of course maybe we can make the substring out from str and use to make a string view strSubView , but there is an extra string creation.

I found that the std::basic_string_view s fifth constructor takes the range of iterators.

template<class It, class End>
constexpr basic_string_view(It first, End last);

But is it only the iterators of the std::string or just std::basic_string_view 's itself? If not for std::string 's iterates why shouldn't be we have one, after all the string view:

describes an object that can refer to a constant contiguous sequence of char-like objects !

Taking the range of contiguous sequence of char, should not we count?

That constructor is added in C++20 . If you are compiling with a C++17 compiler then it isn't present.

You can write a function that does the same thing

std::string_view range_to_view(std::string::iterator first, std::string::iterator last) {
    return first != last ? { first.operator->(), last - first } : { nullptr, 0 };
}

Why can not I create a std::string_view from std::string itertors?

You can, but only since C++20.

But is it only the iterators of the std::string or just std::basic_string_view 's itself?

It's any contiguous iterators of appropriate value type. Both string and string view iterators are accepted. The exact constraints are listed in the documentation.

That means in C++17 there is no way to do it??

There's no way to use a constructor that doesn't exist, but there are several ways of getting the string view that you want. Here's one:

std::string_view strSubView = strView.substr(0, 2);

or without the intermediate variable:

std::string_view strSubView = std::string_view{str}.substr(0, 2);

or if you only have those iterators and have no way of accessing the string:

std::string_view strSubView {&*first, last - first};

As far as it is not safe to dereference the iterator (ie calling to operator* and operator-> on iterator that points to end can crash your app), the only way in C++17 I see is to call string_view::substr() and use iterators only to calculate the size and index.

constexpr std::string_view make_string_view(std::string_view str, 
                                            std::string_view::iterator first, 
                                            std::string_view::iterator last) noexcept
{
    return str.substr(first - str.begin(), last - first);
}

And for std:string use std::string::data() as initial pointer.

std::string_view make_string_view(std::string const& str, 
                                  std::string::const_iterator first, 
                                  std::string::const_iterator last) noexcept
{
    return std::string_view(str.data() + (first - str.begin()), last - first);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM