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::vector
s 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?
1 Answer 1
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
-
1\$\begingroup\$
<assert.h>
is not a C++ header. You probably mean<cassert>
. \$\endgroup\$indi– indi2021年11月27日 19:26:27 +00:00Commented Nov 27, 2021 at 19:26 -
\$\begingroup\$ Thank you very much! :) \$\endgroup\$Dávid Tóth– Dávid Tóth2021年11月28日 13:56:06 +00:00Commented Nov 28, 2021 at 13:56
-
1\$\begingroup\$ @DavidTóth, cool! You got so close that I almost feel like I should have added a spoiler alert ;-) \$\endgroup\$jdt– jdt2021年11月28日 14:06:09 +00:00Commented Nov 28, 2021 at 14:06