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

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. Commented Nov 17, 2015 at 13:59
  • @MSalters Actually, my iterator are already boost::string_ref::iterator :). Commented Nov 17, 2015 at 15:29
  • 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. Commented Mar 19, 2017 at 12:38

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

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.
@MSalters Exactly, at the very least they should be able to accept a pair of boost::string_ref::iterator
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
//  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

2 Comments

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.
@Quentin -- good catch, I updated my post to correct that issue, thank you. Now it's just returning an empty string view when begin==end
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.

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.