Reputation: 9240
Is it possible to get a const iterator from a vector that can only iterate a certain range of the vector before being invalidated?
For example if I have a vector of 10 elements, I want to return an iterator of elements 4 to 7.
pseudo-code:
int main()
{
std::vector<int> vector = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
auto iterator = GetRangedIterator(vector, 4, 7)
for (const int& num : iterator)
print num; // 4, 5, 6, 7
}
Upvotes: 14
Views: 8834
Reputation: 70526
You could use the range-v3 library that is the bases of a Ranges TS which will been part of C++20, but the library already works with C++11 compilers. Here's how:
#include <range/v3/all.hpp>
#include <iostream>
#include <vector>
int main()
{
using namespace ranges;
auto v = view::iota(1, 11) | to_<std::vector<int>>();
std::cout << view::all(v) << '\n';
auto rng = v | view::slice(3, 7);
std::cout << rng << '\n';
}
Upvotes: 6
Reputation: 131626
You can use a span:
auto first_index = 3;
auto last_index = 6;
auto count = last_index - first_index + 1;
auto interesting_nums = gsl::make_span(std::cbegin(vector) + start_index, count);
for(auto& num : interesting_nums) { /* do stuff */ }
Notes:
Upvotes: 0
Reputation: 147
You can use this
for( it = v1.begin() + a; it <= v1.begin() + b; it++ )
The code below is a small demonstration
#include <vector>
#include <iostream>
using namespace std;
int main(){
vector<int> v1;
for( int i = 0; i < 50; i++ ){
v1.push_back( 2*(i+1) );
cout<<v1.at(i)<<" ";
}
cout<<endl;
vector<int>::iterator it;
int a = 5;
int b = 9;
for( it = v1.begin() + a; it <= v1.begin() + b; it++ ){
cout<<(*it)<<" ";
}
cout<<endl;
}
The output is
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100
12 14 16 18 20
Upvotes: 4
Reputation: 490158
This is pretty trivial to do (though I'd call the result a range, not an iterator).
A simple implementation would look something like this:
template <class Iter>
class range {
Iter b;
Iter e;
public:
range(Iter b, Iter e) : b(b), e(e) {}
Iter begin() { return b; }
Iter end() { return e; }
};
template <class Container>
range<typename Container::iterator>
make_range(Container& c, size_t b, size_t e) {
return range<typename Container::iterator> (c.begin()+b, c.begin()+e);
}
As it stands right now, this follows normal C++ conventions (0-based counting, the end you specify is past the end of the range, not in it) so to get the output you asked for, you'd specify a range of 3, 7
, like:
for (int num : make_range(vector, 3, 7))
std::cout << num << ", "; // 4, 5, 6, 7,
Note that the range-based for
loop knows how to use begin
and end
member functions to tell it the range it's going to iterate, so we don't have to deal with invalidating iterators or anything like that, we just have to specify the beginning and end of the range we care about.
Upvotes: 20
Reputation: 11840
There's nothing in the standard library to explicitly do this, but if you're willing to use Boost, you can use the following approach using the range
concept:
auto range = boost::make_iterator_range(v.begin()+3, v.begin()+7);
BOOST_FOREACH(int i, range)
{
cout << i << endl;
}
This should output 4567
Upvotes: 2