# Custom implementation to provide an immutable range of a container without copying it

I needed to pass a const reference to part of a std::vector without copy. I posted the previous version in my earlier question, thank you for the great support! As far as I know this version supports not only std::vectors but any kind of iterator based continuous containers!

Some research, particularly this SO question, suggested that it is not something supported by default(at least in pre-c++20 std), so I created my own code for it:

#include <iterator>
#include <vector>

template <typename Iterator = std::vector<double>::const_iterator>
class ConstVectorSubrange{
public:
using T = typename Iterator::value_type;

ConstVectorSubrange(Iterator start_, std::size_t size_)
: start(start_)
, range_size(size_)
{ }

ConstVectorSubrange(Iterator begin_, Iterator end_)
: start(begin_)
, range_size(std::distance(start, end_))
{ }

const T& operator[](std::size_t index) const{
assert(index < range_size);
return *std::next(start, index);
}
const T& front() const{
return *begin();
}
const T& back() const{
return *std::next(end(), -1);
}
std::size_t size() const{
return range_size;
}
Iterator begin() const{
return start;
}
Iterator end() const{
return std::next(start, range_size);
}

private:
const Iterator start;
const std::size_t range_size;
};


In C++20 the functionality is available in std::span, so I am trying to achieve this with c++17 latest. Target for my code is c++11, but c++17 features are also present in the project I am using this in. I'm not sure I would go up to c++20 as I'm still not sure how widespread it is yet, but I'm still open to it.

An example of using this would be a member function where not the whole array is visible, although copies are to be avoided:

#include <vector>

class BigData{
std::vector<int> big_array = vector<int>(10000);
public:

ConstVectorSubrange get_last_five_thousand_elements(){
return{(big_array.end()-5000), big_array.end()};
}

};


How can this code be improved? I tried to remove the dependent typename, but I could only do that with C++20 std::iter_reference_t. Is there no other way to deduce T explicitly?

• Thanks, I corrected it Nov 27 '21 at 13:38

With C++17 the compiler should be able to deduce the template type automatically by using the following:

template <typename Iterator>
class ConstVectorSubrange {
public:
using T = typename Iterator::value_type;
// ...
}

int main()
{
std::vector v{ 1, 2, 3, 4, 5, 6, 7, 8 };
ConstVectorSubrange range(v.begin() + 2, v.end() - 2);
}


I'm not sure why you have included <iterator> and failed to include <cassert>?

Good:

I like that you can now use the foreach loop:

std::vector v{ 7, 7, 3, 4, 5, 6, 7, 7, 8, 9 };
ConstVectorSubrange vsr(v.begin() + 4, v.end());
for (int i : vsr)
std::cout << i << "\n";


And all the cool stuff from <algorithm>

std::cout << std::count(vsr.begin(), vsr.end(), 7) << "\n";


Ideas:

It would be pretty cool if you could include a step or stride to have a slice of the vector. Something like this:

std::vector v{ 1, 2, 3, 4, 5, 6 };
std::size_t step = 2;
ConstVectorSubrange r(v.begin() + 1, v.end(), step);
for (int i : r)
std::cout << i << "\n";
// expected results 2, 4, 6

• <assert.h> is not a C++ header. You probably mean <cassert>.
– indi
Nov 27 '21 at 19:26
• @indi thanks, updated.
– jdt
Nov 27 '21 at 20:11
• Thank you very much! :) Nov 28 '21 at 13:56
• @DavidTóth, cool! You got so close that I almost feel like I should have added a spoiler alert ;-)
– jdt
Nov 28 '21 at 14:06