Why string_view constructor doesn't take a pair of iterators
Asked Answered
P

3

8

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

Prorogue answered 17/11, 2015 at 6:36 Comment(3)
I'm assuming that your iterators are in fact std::string::iterator ? Because string_ref references an existing string, so you can't construct it from thin air.Coumarin
@Coumarin Actually, my iterator are already boost::string_ref::iterator :).Prorogue
A worth reading chat about this was done at the std future proposal group: groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/… , worth the read.Quintanilla
P
1

Looks like I make a mistake. gsl::string_span do have a constructor that takes begin and end iterator. So, there is nothing problematic with creating string_view from iterator pairs and the lack of it in boost::string_ref is probably just an oversight.

For my case, I end up inheriting from boost::string_ref and add the constructor myself.

Prorogue answered 17/11, 2015 at 15:44 Comment(0)
H
5

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.

Hereby answered 17/11, 2015 at 7:33 Comment(2)
That's not actually a wholly convincing argument. It would be reasonable to construct a boost::string_ref from a std::string::iterator. But even that is not allowed.Coumarin
@Coumarin Exactly, at the very least they should be able to accept a pair of boost::string_ref::iteratorProrogue
V
2

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
//  https://mcmap.net/q/1338087/-why-string_view-constructor-doesn-39-t-take-a-pair-of-iterators/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
Vanegas answered 29/11, 2016 at 0:54 Comment(2)
I just fell into the corner case: if begin == end and they are not dereferenceable (i.e. they both point at the end of a string) then &*begin causes UB.Tupler
@Tupler -- good catch, I updated my post to correct that issue, thank you. Now it's just returning an empty string view when begin==endVanegas
P
1

Looks like I make a mistake. gsl::string_span do have a constructor that takes begin and end iterator. So, there is nothing problematic with creating string_view from iterator pairs and the lack of it in boost::string_ref is probably just an oversight.

For my case, I end up inheriting from boost::string_ref and add the constructor myself.

Prorogue answered 17/11, 2015 at 15:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.