C++ Filteration using lazy iterator - c++

template<typename Iterator>
struct Range {
using LazyIterator = Iterator; // required for accessing the used Iterator type from other locations
Iterator m_begin;
Iterator m_end;
auto begin() { return m_begin; }
auto end() { return m_end; }
};
template<typename Iterator>
Range(Iterator, Iterator) -> Range<Iterator>;
template<typename Iterator, typename Callable>
struct FilteringIterator : Iterator {
Callable callable;
using OriginalIterator = Iterator;
using t = typename OriginalIterator::value_type;
FilteringIterator(const Iterator begin, Callable callable):Iterator(begin),callable(callable){}
Iterator &get_orig_iter() { return ((Iterator &)*this); }
auto operator*() { return callable(*get_orig_iter()); }
};
auto filter = [](auto action) {
return [=]( auto &container) {
using Container = std::decay_t<decltype(container)>;
using Iterator = typename Container::iterator;
using actiontype = decltype(action);
using filter_iterator = FilteringIterator<Iterator, actiontype>;
return Range{filter_iterator{container.begin(),action}, filter_iterator{container.end(),action}};
};
};
I need a lazy iterator that will traverse over a range and filter it lazily.
For example
auto v = std::vector<double>{};
auto odd_gen = views::odds();
for(int i=0; i<5; ++i)
v.push_back(odd_gen() * 2.5);
// v contains {2.5, 7.5, 12.5, 17.5, 22.5} here
new_line();
for(auto a : v | filter(greater_than(15))) // filter is applied lazily as the range is traversed
std::cout << a << std::endl;
// print { 17.5, 22.5} here
but it prints
{0,0,0,0,17.5,22.5}
I want it to only print 17.5, 22.5
how can I achieve that?

Your code never skips elements, it just transforms them. You need to make sure that when the operator*() is invoked, it starts by advancing the iterator while callable returns false, and only then return the value pointed to by the Iterator.
There are corner cases though you have to take care of. If the input ends with elements that don't match the filter, then you run into a problem. You also need to skip over all filtered out elements when operator++() is called. And also think about the case where the filter would not match any elements of the input; in that case you must ensure that begin() is equal to end().

Related

How to implement end sentinel for back_insert_iterator?

I want to fill a container by consequtive values of iterators to elements of another container (often occured real life problem), say:
std::container1< T > c1{/* initialized */};
assert(!c1.empty());
std::continer2< typename std::container1< T >::iterator > c2;
auto it = std::begin(c1), const end = std::end(c1);
do { c2.push_back(it); } while (++it != end);
There is attractive std::iota algorithm in STL, but it is range-based and for std::back_inserter(c2) there is no way to achieve desired currently. However in the next versions of STL I can expect the iota algorithm of the form:
template< typename ForwardIterator, typename EndSentinel, typename T >
void
iota(ForwardIterator first, EndSentinel last, T value)
{
for (; first != last; ++first) {
*first = value;
++value;
}
}
How to implement EndSentinel and operator != (ForwardIterator, EndSentinel) to make above iota stop after exactly c1.size() step of the for loop in iota(std::back_inserter(c1), something(c1, c1.size()), std::begin(c1))?
There is no sentinel for std::back_insert_iterator (or any OutputIterator) and also no equality operator, because an output iterator is an "unlimited sequence": You can append elements to the end of a container or write to a file until you run out of memory or disk space.
However, it makes sense to have an output iterator with a sentinel if you need to call an algorithm which expects an "output sentinel" (because not expecting one may be unsafe if the output is a "limited sequence", such as a pre-allocated std::vector). Such an algorithm could look like:
template<typename InIter, typename InSentinel, typename OutIter, typename OutSentinel>
OutIter modernAlgorithm(InIter first, InSentinel last, OutIter outFirst, OutSentinel outLast);
In this case, all you need is a trivial sentinel, which compares unequal to everything. See also this answer.
template<typename T>
struct TrivialSentinel
{
bool operator==(const T&) { return false; }
bool operator!=(const T&) { return true; }
friend bool operator==(const T&, TrivialSentinel&) { return false; }
friend bool operator!=(const T&, TrivialSentinel&) { return true; }
};
modernAlgorithm(v.begin(), v.end(), std::back_inserter(r), TrivialSentinel<decltype(std::back_inserter(r))>());
(This may seem odd, but it does make sense if you consider that even if you repeat the same operation *out = expr on the same value of out, the output will be in a different state each time, so in a certain sense, no two output iterators are ever necessarily equivalent...)
However, older algorithms often don't allow the iterator and sentinel to have different types:
template<typename InIter, typename OutIter>
OutIter olderAlgorithm(InIter first, InIter last, OutIter outFirst, OutIter outLast);
In this case, you can write a sub class or wrapper of std::back_insert_iterator, which has a default constructor and always compares unequal to itself.
This is easy in C++20, where std::back_insert_iterator has a default constructor:
// C++20
template<typename C>
struct BackInsertIteratorWithSentinel : public std::back_insert_iterator<C>
{
BackInsertIteratorWithSentinel() {} // C++20 only
BackInsertIteratorWithSentinel(C& c) : std::back_insert_iterator<C>(c) {}
bool operator==(const BackInsertIteratorWithSentinel&) { return false; }
bool operator!=(const BackInsertIteratorWithSentinel&) { return true; }
};
template<typename C>
BackInsertIteratorWithSentinel<C> BackInserterWithSentinel(C& c)
{
return BackInsertIteratorWithSentinel<C>(c);
}
template<typename C>
BackInsertIteratorWithSentinel<C> BackInserterWithSentinel()
{
return BackInsertIteratorWithSentinel<C>();
}
olderAlgorithm(v.begin(), v.end(), BackInserterWithSentinel(r), BackInserterWithSentinel<std::vector<int> >());
Note that even in C++20, std::back_insert_iterator does not have an equality operator.
If you have to support older versions of C++, then you may have to implement your own std::back_insert_iterator from scratch, or use boost::optional or in-place construction to work around the lack of a default constructor.
Full test program for C++20
I dont think you can do it - or maybe I dont understand your question, but..
according to http://en.cppreference.com/w/cpp/algorithm/iota, this algorithm works on existing range of elements - so it does not make sense to use it with: std::back_inserter as first iterator which basicly is used to insert elements.
I want to fill a container by consequtive values of iterators to elements of another container
a different solution which uses generate_n:
live
std::vector<int> src = {0,1,2,3};
std::vector<std::vector<int>::iterator> dst;
std::generate_n(std::back_inserter(dst), src.size(), [it=src.begin()]() mutable {return it++;});
Your question includes an iota implementation which is different than the one in the standard I believe. Here is the standard version I know http://en.cppreference.com/w/cpp/algorithm/iota.
Your iota (which I will rename it as miota in my code) allows different type of iterators for begin and end.
What you want in the algorithm is; end sentinel needs to be different from begin (the inserter) until all values are processed. For processing values you only take one object and you use increment and copy-construction on that object.
Therefore, your end sentinel should know about the value processing and when finished the end sentinel should become equal to the inserter somehow.
I did it via holding begin/end iterators of the original container in a class called IotaHelper. This uses shared_ptr for sharing state with the sentinel class which is called IotaEndSentinel.
When you increment the value inside miota, it actually increments the begin iterator of the IotaHelper. When you check equality with the inserter and the sentinel it actually checks the iterator equality inside the IotaHelper.
All code with a basic example is here:
#include <iterator>
#include <numeric>
#include <vector>
#include <iostream>
#include <utility>
#include <memory>
template< typename ForwardIterator, typename EndSentinel, typename T >
void miota(ForwardIterator first, EndSentinel last, T value)
{
for (; first != last; ++first) {
*first = value;
++value;
}
}
template<typename Container>
struct IotaHelper
{
using Iterator = typename Container::iterator;
using IteratorPair = std::pair<Iterator, Iterator>;
IotaHelper(Iterator begin, Iterator end)
:
pair(std::make_shared<IteratorPair>(begin, end))
{ }
operator Iterator()
{
return pair->first;
}
IotaHelper& operator++()
{
++pair->first;
return *this;
}
std::shared_ptr<IteratorPair> pair;
};
template<typename Container>
struct IotaEndSentinel
{
using Helper = IotaHelper<Container>;
using Iterator = typename Helper::Iterator;
IotaEndSentinel(const Helper& helper)
:
helper(helper)
{}
template<typename C>
friend bool operator!=(const std::back_insert_iterator<C>& bii,
const IotaEndSentinel& sentinel)
{
return sentinel.helper.pair->first != sentinel.helper.pair->second;
}
Helper helper;
};
int main()
{
using Container0 = std::vector<int>;
using Container1 = std::vector<Container0::iterator>;
Container0 c0 = {1, 2, 3, 4, 5};
Container1 c1;
IotaHelper<Container0> iotaHelper(c0.begin(), c0.end());
miota(std::back_inserter(c1),
IotaEndSentinel<Container0>(iotaHelper),
iotaHelper);
std::cout << "Result: ";
for (auto iter : c1)
{
std::cout << *iter << ", ";
}
std::cout << std::endl;
}
I have tried to do this because it was fun. But please don't use this method for hacking output iterators like back_insert_iterator and make a generic method for yourself for different containers.
template<typename SourceContainer, typename IteratorContainer>
void FillIterators(SourceContainer& sc, IteratorContainer& ic)
{
for (auto iter = sc.begin(); iter != sc.end(); ++iter)
{
ic.insert(ic.end(), iter);
}
}
EDIT:
After using heap-allocation that code was smelling to me. Instead of trying to reason about the "value and the process" we can reason about the "iterators and the process".
We can build an iterator-wrapper which contains the process iterator and the insert iterator together.
When the algorithm needs to dereference the wrapper, it will return the insert iterator.
When the algorithm needs to compare to other "wrapper or sentinel", wrapper will compare the process iterator.
In the end we can use such iterator for both std::iota and your miota.
Complete example is here:
#include <iterator>
#include <numeric>
#include <vector>
#include <iostream>
#include <utility>
#include <memory>
template< typename ForwardIterator, typename EndSentinel, typename T >
void miota(ForwardIterator first, EndSentinel last, T value)
{
for (; first != last; ++first) {
*first = value;
++value;
}
}
template<typename InsertIterator, typename Iterator>
struct InsertWrapper
{
InsertWrapper(const InsertIterator& inserter, const Iterator& iter)
:
inserter(inserter),
iter(iter)
{ }
bool operator!=(const InsertWrapper& other) const
{
//only compare process iterators
return iter != other.iter;
}
bool operator!=(const Iterator& sentinel) const
{
//compare process iterator against the sentinel
return iter != sentinel;
}
InsertIterator& operator*()
{
//return inserter for dereference
return inserter;
}
InsertWrapper& operator++()
{
//iterate inserter as the process progresses
++inserter;
++iter;
return *this;
}
InsertIterator inserter;
Iterator iter;
};
template<typename InsertIterator, typename Iterator>
InsertWrapper<InsertIterator, Iterator> WrapInserter(const InsertIterator& inserter,
const Iterator& iter)
{
return InsertWrapper<InsertIterator, Iterator>(inserter, iter);
}
int main()
{
using Container0 = std::vector<int>;
using Container1 = std::vector<Container0::iterator>;
Container0 c0 = {1, 2, 3, 4, 5};
Container1 c1;
//use wrapper as usual iterator begin/end
std::iota(WrapInserter(std::back_inserter(c1), c0.begin()),
WrapInserter(std::back_inserter(c1), c0.end()),
c0.begin());
std::cout << "std::iota result: ";
for (auto iter : c1)
{
std::cout << *iter << ", ";
}
std::cout << std::endl;
c1.clear();
miota(WrapInserter(std::back_inserter(c1), c0.begin()),
c0.end(), //end iterator as sentinel
c0.begin());
std::cout << "miota result: ";
for (auto iter : c1)
{
std::cout << *iter << ", ";
}
std::cout << std::endl;
}

Convert the end() iterator to a pointer

To get to the point: is the following safe ?
vector<int> v;
int const* last = &*v.end();
// last is never dereferenced
My concern is that the trick to get a plain old pointer from an iterator forces to dereference the end() iterator, which is not valid... even if it is just to take the pointer back!
Backgroud: I am trying to create a collection of entries indexed by arbitrary types (especially integers and pointer to objects).
template<class IT>
/// requires IT implements addition (e.g. int, random-access iterator)
class IndexingFamily {
public:
using IndexType = IT;
IndexingFamily(IndexType first, IndexType last);
int size() const;
IndexType operator[](int i) const;
private:
IndexType first;
IndexType last;
};
template<class IT> IndexingFamily<IT>::
IndexingFamily(IndexType first, IndexType last)
: first(first)
, last(last) {}
template<class IT> auto IndexingFamily<IT>::
size() const -> int {
return last-first;
}
template<class IT> auto IndexingFamily<IT>::
operator[](int i) const -> IndexType {
return first+i;
}
template<class IT, class ET>
struct IndexedEntry {
using IndexType = IT;
using EntryType = ET;
IndexType index;
EntryType entry;
};
template<class IT, class ET>
class CollectionOfEntries {
public:
using IndexType = IT;
using EntryType = ET;
/// useful methods
private:
IndexingFamilyType indexingFamily;
vector<EntryType> entries;
};
struct MyArbitraryType {};
int main() {
MyArbitraryType obj0, obj1, obj2;
vector<MyArbitraryType> v = {obj0,obj1,obj2};
using IndexType = MyArbitraryType const*;
IndexingFamily<IndexType> indexingFamily(&*v.begin(),&*v.end());
using EntryType = double;
using IndexedEntryType = IndexedEntry<IndexType,EntryType>;
IndexedEntry entry0 = {&obj0,42.};
IndexedEntry entry1 = {&obj1,43.};
vector<IndexedEntryType> entries = {entry0,entry1};
CollectionOfEntries coll = {indexingFamily,entries};
return 0;
}
Dereferencing an end() iterator gives undefined behaviour, with any standard container.
For a vector you can get a pointer corresponding to the end() iterator using
pointer_to_end = v.empty() ? 0 : (&(*v.begin()) + v.size());
or
pointer_to_end = v.data() + v.size(); // v.data() gives null is size is zero
The check of v.empty() is needed since, if v is empty, v.begin() == v.end(). For C++11 or later, use of nullptr instead of 0 in the above is often considered preferable.
The iterator returned by member function end() "points" after the last element of a vector. You may not dereference it. Otherwise the program will have undefined behavior.
You can get the corresponding pointer the following way
vector<int> v;
int const *last = v.data() + v.size();
If you want to use the iterator returned by the member function end() you can write
vector<int> v;
int const *last = v.data() + std::distance( v.begin(), v.end() );
Take into account that member function data() returns a raw pointer of the memory extent occupied by vector's data.

gtest/gmock matcher for subsequence between a pair of iterators

Suppose I have a mock function with a signature as follows
class MyMock
{
MOCK_METHOD4( f, void( X, Iterator begin, Iterator end, Y ) );
};
I want to write an EXPECT_CALL that has the effect of using ContainerEq, ElementsAre or any other container matcher on the sequence [begin, end). Ideally something like a 'Range' matcher would exist, e.g.:
MyMock m;
EXPECT_CALL( m, f(_,_,_,_) ).With(Args<1,2>(Range(ElementsAre(a,b,c)));
Is there such a thing? How could I make one that allows using all of the various container matches to be used without rewriting them?
Such IteratorRange will work in most cases - for limitation look into matcher body:
MATCHER_P(IteratorRange, param, "")
{
auto begin = get<0>(arg);
auto end = get<1>(arg);
// these two lines might be weak point of this matcher implementation...
// I mean:
// 1. constructing vector might be not supported
// e.g. object are not copyable)
// 2. copying objects from range might "change" the tested code behavior
// e.g. copy is badly implemented
// 3. it is for sure "performance" degradation
using value_type = typename std::iterator_traits<decltype(begin)>::value_type;
std::vector<value_type> range{begin, end};
Matcher<decltype(range)> matcher = param;
return matcher.MatchAndExplain(range, result_listener);
}
It can be used like this:
TEST(A,A)
{
int a,b,c;
std::vector<int> values{ a,b,c };
MyMock m;
EXPECT_CALL( m, f(_,_,_,_) ).With(Args<1,2>(IteratorRange(ContainerEq(values))));
m.f(X{}, values.begin(), values.end(), Y{});
}
[UPDATE]
The overcome the drawbacks of this internal copying a range into container - you need to invent the light container - like this one:
template <typename Iterator>
class RangeView
{
public:
using iterator = Iterator;
using const_iterator = Iterator;
using value_type = typename std::iterator_traits<Iterator>::value_type;
RangeView(Iterator begin, Iterator end) : beginIter(begin), endIter(end) {}
iterator begin() const { return beginIter; }
iterator end() const { return endIter; }
std::size_t size() const { return std::distance(beginIter, endIter); }
bool operator == (const RangeView& other) const
{
return size() == other.size() && std::equal(beginIter, endIter, other.beginIter);
}
private:
Iterator beginIter, endIter;
};
Plus some helper function to make it easier to use this class:
template <typename Iterator>
void PrintTo(RangeView<Iterator> const& range, std::ostream* os)
{
*os << "{";
for (auto&& e: range) *os << "[" << PrintToString(e) << "]";
*os << "}";
}
template <typename Iterator>
RangeView<Iterator> makeRangeView(Iterator begin, Iterator end)
{
return RangeView<Iterator>(begin, end);
}
template <typename Container>
auto makeRangeView(Container const& container)
{
return makeRangeView(std::begin(container), std::end(container));
}
Note that if you use boost in your project - you can use range from boost - you do not need to "reinvent the wheel".
Then - light matcher can be defined without these drawbacks:
MATCHER_P(IteratorRangeLight, param, "")
{
auto begin = get<0>(arg);
auto end = get<1>(arg);
auto range = makeRangeView(begin, end);
Matcher<decltype(range)> matcher = param;
return matcher.MatchAndExplain(range, result_listener);
}
Then - use it like this:
TEST(A,A)
{
int a=1,b=2,c=3;
std::vector<int> values{ a,b,c };
MyMock m;
EXPECT_CALL( m, f(_,_,_,_) ).
With(Args<1,2>(IteratorRangeLight(ContainerEq(makeRangeView(values)))));
// ^^^^^^^^^^^^^
// note that you need to use makeRangeView also within the matcher
m.f(X{}, values.begin(), values.end(), Y{});
}

Insert order std::map

I would create an associative array (like std:: map) that stores the elements in order of insertion. I wrote this class:
template <typename K, typename V>
class My_Map : public std::unordered_map<K,V>
{
public:
V& operator[]( const K&& key )
{
typename std::unordered_map<K,V>::iterator __i = find(key);
if (__i == std::unordered_map<K,V>::end()) //se non l'ho trovato...
{
__i = insert(__i, std::make_pair(std::move(key), V()) );
mHistory.push_back(__i);std::cout<<"Sto inserendo: "<<key<<std::endl;
}
return (*__i).second;
}
typename std::unordered_map<K,V>::iterator cbegin() const
{
return *mHistory.cbegin();
}
typename std::unordered_map<K,V>::iterator cend() const
{
return *mHistory.cend();
}
private:
std::list<typename std::unordered_map<K,V>::iterator> mHistory;
};
using namespace std;
int main()
{
My_Map<string,int> myMap;
myMap["1"] = 1;
myMap["23"] = 23;
myMap["-3"] = 3;
myMap["23"] = 28;
myMap["last element"] = 33;
for (auto x = myMap.cbegin(); x != myMap.cend(); ++x)//{std::cout<<"sn dentro\n";}
cout<<(*x).first <<"\t"<<x->second<<endl;
}
I used unordered_map instead std::map because std::map mix iterators when I insert new element.
This code have a problem: the for in main() fails with a segmentation fault. The iterators passed with cbegin() and cend() are not valid...why? What's wrong?
The first thing is that you can't dereference an end iterator of a list. Secondly, I also doubt if yourMap.cend will be necessarily reachable from yourMap.cbegin.
It looks like you might need an adaptor for the list iterator that automatically dereferences the stored map iterator pointer to map item.
In any case, you need to iterate over the list, not from a random point in the unordered_map to another random point therein.
Also: adding elements can cause rehashing, which will invalidate iterators (but not pointers or references to elements). You should not even store iterators into an unordered_map.

Limit STL algorithms to N elements

(Inspired by a comment from nakiya)
Many STL algorithms take a range as a pair of iterators. For instance, for_each(begin, end, &foo);. Obviously, if distance(begin, end) >= N, and begin is a random-access iterator, then for_each(begin, begin+N, &foo); applies foo only to the first N elements.
Now is there a clean, generic alternative if either of these two conditions is not met?
There is no generic full solution without changing the iterator type.
Proof: suppose that the iterator type is only an InputIterator, so begin actually refers to (for example) a stream, and end is a special-case marker iterator, which will compare equal to the "real" iterator once the real iterator has read EOF.
Then any use of begin to try to work out a new value of end to pass to the algorithm, will "consume" the original value of begin, since that's how InputIterators work.
What you could do is write an iterator wrapper class, such that the iterator counts how many times it has been incremented, and compares equal to an "end" iterator once it has been incremented N times. N could be a template parameter, or a constructor parameter to one or other of the iterators.
Something like this. I've tested it compiles and works for me. Still to do - I'm currently only handling one of your two situations, "not a random-access iterator". I don't also handle the other, "distance < N".
#include <iterator>
template <typename It>
class FiniteIterator : public std::iterator<
typename std::iterator_traits<It>::iterator_category,
typename std::iterator_traits<It>::value_type> {
typedef typename std::iterator_traits<It>::difference_type diff_type;
typedef typename std::iterator_traits<It>::value_type val_type;
It it;
diff_type count;
public:
FiniteIterator(It it) : it(it), count(0) {}
FiniteIterator(diff_type count, It it = It()) : it(it), count(count) {}
FiniteIterator &operator++() {
++it;
++count;
return *this;
}
FiniteIterator &operator--() {
--it;
--count;
return *this;
}
val_type &operator*() const {
return *it;
}
It operator->() const {
return it;
}
bool operator==(const FiniteIterator &rhs) const {
return count == rhs.count;
}
bool operator!=(const FiniteIterator &rhs) const {
return !(*this == rhs);
}
FiniteIterator operator++(int) {
FiniteIterator cp = *this;
++*this;
return cp;
}
FiniteIterator operator--(int) {
FiniteIterator cp = *this;
--*this;
return cp;
}
};
Note that the second constructor only takes an iterator because the underlying type might not be default constructible (if it's only an InputIterator). In the case where the caller is creating an "end" iterator it doesn't use it, because it won't be valid once the other copy is incremented.
If the underlying iterator type is RandomAccess, then this wrapper isn't needed/wanted. So I provide a helper template function, that does the type deduction the same way back_inserter does for back_insert_iterator. However, in the case where its parameter type is an iterator of random-access category, the helper shouldn't return FiniteIterator<T>, but just T:
template <typename Iterator, typename Category>
struct finite_traits2 {
typedef FiniteIterator<Iterator> ret_type;
static ret_type plus(Iterator it, typename std::iterator_traits<Iterator>::difference_type d) {
return ret_type(d, it);
}
};
template <typename Iterator>
struct finite_traits2<Iterator, std::random_access_iterator_tag> {
typedef Iterator ret_type;
static ret_type plus(Iterator it, typename std::iterator_traits<Iterator>::difference_type d) {
return it + d;
}
};
template <typename Iterator>
struct finite_traits {
typedef typename std::iterator_traits<Iterator>::iterator_category itcat;
typedef typename finite_traits2<Iterator, itcat>::ret_type ret_type;
static ret_type plus(Iterator it, typename std::iterator_traits<Iterator>::difference_type d) {
return finite_traits2<Iterator, itcat>::plus(it, d);
}
};
template <typename Iterator, typename Distance>
typename finite_traits<Iterator>::ret_type finite_iterator(Iterator it, Distance d) {
return finite_traits<Iterator>::plus(it, d);
}
template <typename Iterator>
typename finite_traits<Iterator>::ret_type finite_iterator(Iterator it) {
return finite_traits<Iterator>::plus(it, 0);
}
Example usage (and minimal test):
#include <iostream>
#include <typeinfo>
#include <list>
struct MyIterator : std::iterator<std::bidirectional_iterator_tag, int> {
difference_type count;
};
int main() {
std::cout << typeid(MyIterator::iterator_category).name() << "\n";
std::cout << typeid(FiniteIterator<MyIterator>::iterator_category).name() << "\n";
std::cout << typeid(MyIterator::difference_type).name() << "\n";
std::cout << typeid(FiniteIterator<MyIterator>::difference_type).name() << "\n";
int a[] = {1, 2, 3, 4, 5};
std::copy(finite_iterator(a), finite_iterator(a,4), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
std::list<int> al(finite_iterator(a), finite_iterator(a,4));
std::cout << al.size() << "\n";
std::copy(finite_iterator(al.begin()), finite_iterator(al.begin(),3), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
}
Caution: finite_iterator(x, 1) == finite_iterator(++x, 0) is false, even for a forward iterator or better. Finite iterators are only comparable if they are created from the same starting point.
Also, this still isn't complete. For example std::reverse doesn't work, because for the purposes of accessing the referand, finite_iterator(x, 1) is "pointing at" x.
Currently the following happens to work:
std::list<int>::iterator e = al.begin();
std::advance(e,3);
std::reverse(finite_iterator(al.begin()), finite_iterator(e,3));
So I'm not far off, but that's not a good interface. I would need to think more about the case of Bidirectional iterators.
There is already fill_n and generate_n, there is no foreach_n (or for_n would probably be more appropriate) but it is easy enough to write one.
template< typename FwdIter, typename Op, typename SizeType >
void for_n( FwdIter begin, SizeType n, Op op )
{
while( n-- )
{
op(*begin);
++begin;
}
}
You could do op(*begin++) but although it is less typing it may generate more code to copy the iterator. size_type is numeric so doing post-increment is no less efficient and here is a case where it is useful.
I believe you could create a wrapper iterator type similar to boost::counting_iterator which would keep together both an increment and the underlying iterator, and would compare equal to an "end" iterator as soon as the increment exceeds the maximum value.