Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why string_view constructor doesn't take a pair of iterators

Both string_ref in boost and string_span in GSL doesn't define constructor that takes a pair of iterator. What is the reason of this decision ?

Usually it's not a big deal, I can just create string_ref like this :

boost::string_ref s(start, std::distance(start, finish));

but the reason I want constructor that take a pair of iterators is because I have code that look like this:

template<typename Type, typename Iterator>
void func(const Iterator& begin, const Iterator& end)
{
    Type s(begin, end);
    //do stuff with s
}

Currently, I can call it like this :

func<std::string>(start, finish)

I want to change it to :

func<boost::string_ref>(start, finish) //compile error

but that code won't compile because the lack of constructor taking a pair of iterator in string_ref

like image 335
Kamil Zubair Avatar asked Nov 17 '15 06:11

Kamil Zubair


People also ask

What is the difference between string and 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 string_view be passed 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.

Does string_view allocate?

string_view is a slice in an existing buffer, it does not require a memory allocation.


2 Answers

boost::string_ref is a simple reference to a string in the form of a pointer to a contiguous block of memory with a predefined length. Since iterators are much more generic, you cannot assume that your start, finish range refers to anything like a contiguous block of memory.

On the other hand, a std::string can be constructed from a range defined by Iterators because it will simply make a copy of the range's values, regardless of what the underlying data structure is.

like image 121
matz Avatar answered Oct 18 '22 10:10

matz


Helper function I created, hopefully someone else can find this useful. Briefly tested MSVC14/boost 1.59, MSVC17/boost 1.64, MSVC17/C++17

#include <boost/utility/string_ref.hpp>

// todo:  change to std::basic_string_view<charT> in C++17
template <typename charT> using basic_string_view_type = boost::basic_string_ref<charT>;    

// Creates a string view from a pair of iterators
//  http://stackoverflow.com/q/33750600/882436
template <typename _It>
inline constexpr auto make_string_view( _It begin, _It end )
{
    using result_type = basic_string_view_type<typename std::iterator_traits<_It>::value_type>;

    return result_type{
        ( begin != end ) ? &*begin : nullptr
        ,  (typename result_type::size_type)
        std::max(
            std::distance(begin, end)
            , (typename result_type::difference_type)0
        )
     };
}   // make_string_view
like image 42
Tom Avatar answered Oct 18 '22 11:10

Tom