7

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?

3
  • That constructor is added in C++20. If you are compiling with a C++17 compiler then it isn't present. It works if you target C++20 Commented Aug 27, 2021 at 13:15
  • "we can make the substring out from str... but there is an extra string creation." std::string_view can create substrings too. strSubView = strView.substr( 0, 2 );. That would be comparable to what you are attempting. Commented Aug 27, 2021 at 13:17
  • @Caleth Oh yes, that was just under my eye, but I didn't notice the language tag in cppreference. That means in C++17 there is no way to do it?? Commented Aug 27, 2021 at 13:19

3 Answers 3

7

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 };
}
Sign up to request clarification or add additional context in comments.

4 Comments

I hope the std::string_view will be moce constructed where ever I call the range_to_view ?
@Const it's an unmaterialised temporary, it gets constructed in place at the call site
In case if first points to end, the operator-> will fail
@DmytroOvdiienko no, you'll get a pointer one past the end
4

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};

4 Comments

Thanks for the explanation, I prefer a helper function rather until I am able to use C++20.
&*first may crash if first points to end
&*first is the same as first.operator->() in Caleth's answer, right?
@Peter-ReinstateMonica Effectively yes.
0

As far as it is not safe to dereference the iterator (i.e. 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);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.