I'm trying to write an iterator that iterates on multiple (sorted) lists.
I have one that works but I'd like to improve it.
Here's what I have for now.
#ifndef __multi_iterator__
#define __multi_iterator__
#include <list>
template <typename T>
class multi_iterator
{
private:
typedef typename std::list<T>::const_iterator iterator;
typedef std::list<iterator> iterator_list;
public:
multi_iterator();
multi_iterator(const multi_iterator<T>& other);
multi_iterator& operator = (const multi_iterator<T>& other);
virtual ~multi_iterator();
void add_list(const std::list<T>& it);
const T& operator * ();
multi_iterator<T>& operator ++ ();
multi_iterator<T> operator ++ (int unused);
bool operator == (const multi_iterator<T>& other);
bool operator != (const multi_iterator<T>& other);
protected:
iterator_list _it_list;
iterator_list _end_list;
private:
iterator& next();
};
template <typename T>
multi_iterator<T>::multi_iterator()
: _it_list()
{
}
template <typename T>
multi_iterator<T>::multi_iterator(const multi_iterator<T>& other)
: _it_list(other._it_list)
{
}
template <typename T>
multi_iterator<T>& multi_iterator<T>::operator = (const multi_iterator<T>& other)
{
_it_list = other._it_list;
}
template <typename T>
multi_iterator<T>::~multi_iterator<T>()
{
}
template <typename T>
void multi_iterator<T>::add_list(const std::list<T>& l)
{
_it_list.push_back(l.begin());
_end_list.push_back(l.end());
}
template <typename T>
const T& multi_iterator<T>::operator * ()
{
return *(next());
}
template <typename T>
multi_iterator<T>& multi_iterator<T>::operator ++ ()
{
++(next());
return *this;
}
template <typename T>
typename multi_iterator<T>::iterator& multi_iterator<T>::next()
{
typename iterator_list::iterator it = _it_list.begin();
typename iterator_list::iterator end_it = _end_list.begin();
typename iterator_list::iterator cur_it = _it_list.end();
for (; it != _it_list.end(); ++it)
{
if (*it != *end_it)
{
if ((cur_it == _it_list.end()) || (**it < **cur_it))
{
cur_it = it;
}
}
++end_it;
}
return *cur_it;
}
template <typename T>
multi_iterator<T> multi_iterator<T>::operator ++ (int unused)
{
return ++(*this);
}
template <typename T>
bool multi_iterator<T>::operator == (const multi_iterator<T>& other)
{
return _it_list == other._it_list;
}
template <typename T>
bool multi_iterator<T>::operator != (const multi_iterator<T>& other)
{
return !(*this == other);
}
#endif /* defined(__multi_iterator__) */
Here are the questions I've been pondering:
What should a C++ iterator do when it reaches the end (trying to look like stdlib). Throw an exception?
I don't think my keeping the list of iterator "ends" is elegant. Neither is my way to find if all iterators are at the end in next(). Does anyone have a cleaner solution?
Currently next() runs in linear time and is called for both * and ++ operators. I'm thinking I could save the current iterator and get the * operator to run in constant time. Also, If I sort my list each time I call ++, would ++ run in nlog(n)? I heard that this can be done in log(n) time and I can't really find a way to do that. What are your thoughts on complexity and optimization for this?
What you're trying to do is pretty well covered by zip iterators -- the Boost.Iterator library provides one. Check out their implementation.
You should also check out this discussion if you need to be able to add containers dynamically:
Zip Several Iterators in C++
What should a C++ iterator do when it reaches the end (trying to look like stdlib). Throw an exception?
It should become singular; that is, it must remain able to be compared with other iterators from the same sequence, but does not need to be dereferencable. Specifically, it must compare equal to another past-the-end iterator, and not equal to any non-singular iterator.
It certainly shouldn't throw an exception.
Related
I am trying to get Predecessor and Successor of a vertex from a directed graph implemented with adjacency list.
here s a brief description of my class :
template <class T>
class Digraph
{
public:
Digraph();
~Digraph();
void predecessor(T u);
void successor(T u, T v);
private:
std::map<T, std::set<T>> graphe;
}
Here is what I tried :
template <class T>
const std::set<T> Digraph<T>::predecessor(T u) const
{
std::set<T> p;
int index = 0;
for (auto it = graphe.begin(); it != graphe.end(); ++it, index++)
{
for(T el : *it) //I got the error here
{
if (el == u)
p.insert(index);
}
}
return p;
}
template <class T>
const std::set<T> Digraph<T>::successor(T u) const
{
return graphe.at(u);
}
I get the error in the inner loop.
Does anyone have an idea for an implementation? or can help me by telling me what i forgot.
Searching through the entire graph to find predecessors is a possibly costly operation. You would make your life much easier if you just stored all back-edges in a separate, identical structure:
std::map<T, std::set<T>> inverted;
Then, your member functions would be quite trivial:
template <typename T>
std::set<T> const& Digraph<T>::successor(T const& v) const {
return graph.at(v);
}
template <typename T>
std::set<T> const& Digraph<T>::predecessor(T const& u) const {
return inverted.at(u);
}
Note that the return type is an std::set<T> const& instead of an std::set<T>. This means that you don't copy the entire set.
For insertion the code becomes:
graph[v].insert(u);
inverted[u].insert(v); // new line
However, if you really want to keep your expensive lookup, maybe because it happens really seldom you can do it like this:
template <class T>
std::set<T> Digraph<T>::predecessor(T const& u) const {
std::set<T> p;
for (auto const& [v, set]: graph)
for(auto const& w : set)
if (u == w) {
p.insert(v);
break;
}
return p;
}
Please note however, that this will create copies of the values stored in your graph. If you only have integers, that's no issue. But if you have class-objects in there, copying might not be what you want.
What I am doing
I am practicing c++ after 3 years. I needed to learn fast and broadly, so this example i am trying to solve might look odd to you.
I am using c++20, gcc 10.2.
I wanted to make a pythonic enumerate function that
Takes any container<T>
Yields std::tuple<int, T>
Where T is the type of items in the container
I wanted to try applying pythonic range as an argument of enumerate which
Takes (int start, int end, int step)
Yields int i from start to end every step
range (Not my code, I only added step functionality)
template <typename T>
class range_iterator;
template <typename T>
class range_impl
{
const T start_;
const T stop_;
const T step_;
public:
range_impl(T start, T stop, T step) : start_{start}, stop_{stop}, step_{step} {};
range_impl(T start, T stop) : start_{start}, stop_{stop}, step_{1} {};
range_impl(T stop) : start_{0}, stop_{stop}, step_{1} {};
range_iterator<T> begin() const
{
return range_iterator<T>{start_, step_};
}
range_iterator<T> end() const
{
return range_iterator<T>{stop_, step_};
}
};
template <typename T>
class range_iterator
{
T current_;
const T step_;
public:
range_iterator(T init, T step) : current_{init}, step_{step} {};
range_iterator<T> &operator++()
{
current_ += step_;
return *this;
}
bool operator!=(const range_iterator<T> &rhs) const
{
return current_ != rhs.current_;
}
T operator*() const
{
return current_;
}
};
template <typename T>
range_impl<T> range(const T start, const T stop, const T step)
{
return range_impl<T>(start, stop, step);
}
template <typename T>
range_impl<T> range(const T start, const T stop)
{
return range_impl<T>(start, stop);
}
template <typename T>
range_impl<T> range(const T stop)
{
return range_impl<T>(stop);
}
Can be used like following
#include <iostream>
int main()
{
for(auto i: range(0, 100 2)
{
std::cout << i << std::endl;
}
}
Problem code: enumerate
template <typename T>
class enumerate_iterator;
// Here, T should be a type of a container that contains type X
template <typename T>
class enumerate_impl
{
T impl;
public:
enumerate_impl<T>(T impl) : impl{impl} {/* empty */};
enumerate_iterator begin() const
{
return enumerate_iterator{impl.begin()};
}
enumerate_iterator end() const
{
return enumerate_iterator{impl.end()};
}
};
// Here, T should be a type of a iterator, I think. Confused myself.
template <typename T>
class enumerate_iterator
{
T iterator;
int i;
public:
enumerate_iterator(T iterator) : iterator{iterator}, i{0} {/* empty body */};
enumerate_iterator<T> &operator++()
{
i++;
iterator++;
return *this;
}
bool operator!=(const enumerate_iterator<T> &rhs) const
{
return iterator != rhs.iterator;
}
std::tuple operator*() const
{
return {i, *iterator};
}
};
template <typename T>
enumerate_impl<T> enumerate(T impl)
{
return enumerate_impl<T>{impl};
}
Expected usage
#include <iostream>
int main()
{
for (auto &[i, j] : enumerate(range(0, 100, 2)))
{
std::cout << i << " " << j << std::endl;
}
}
Gotten error (There actually tons of compilation error, but I want to try more on the others).
utility.cpp:186:20: error: deduced class type 'tuple' in function return type
186 | std::tuple operator*() const
I guessed this is complaining that you didn't tell me what type the tuple contains. But the thing is, I don't know what type T iterator contains. How would I tell return type is std::tuple<int, type T contains>?
Thanks for reading this long long question.
I think that perhaps, for enumerate_iterator, you might want its template type T to be a "base element type", not some compound "iteration type".
For example, if you were to choose to implement your iteration using raw memory pointers, then the enumerate_iterator's data member called iterator would have type T* (instead of its current T type).
And then, in that case, the definition of operator*() would be programmed as having a return type of std::tuple<int,T>
I am trying to implement an iterator for a binary search tree. I was asked not to use any STL in my iterator. I only have to override the operators: ++, operator*, and !=. I get an error with the operator*: "no *operator matches this operands. Operands types are *iterator<std::string>". I'm using a template library, so I'm not sure why it's not working.
Here's my code:
template <typename T>
class Iterator : public std::iterator<std::forward_iterator_tag, {
public:
Iterator(TreeNode<T>* root)
{
this->current = root;
}
template <typename T>
bool operator!=(Iterator<T> const & other) const
{
return this->current != other.current;
}
template <typename T>
T &operator*() const {
return current->element;
}
Iterator operator++()
{
current = current->nextInorder();
return *this;
}
Iterator operator++(int dummy)
{
TreeNode<T> temp = current;
current = current->nextInorder();
return *temp;
}
private:
TreeNode<T>* current;
void nextInorder()
{
if (current->element == NULL)return;
else {
nextInorder(current->left);
nextInorder(current->element);
nextInorder(current->right);
}
}
};
The code is not well-pasted (see the class Iterator...line).
I would recommend removing template <typename T> on bool operator!=(Iterator<T> const & other) const and T &operator*() const methods. Because the T is the one used for the class instantiation.
Context: C++03 only + the use of boost is authorized
I'd like to raise the same question as in
How to negate a predicate function using operator ! in C++?
... but with an overloaded boolean predicate, that is:
struct MyPredicate
{
bool operator()(T1) const;
bool operator()(T2) const;
};
Clearly, MyPredicate cannot be derived from std::unary_function as it is impossible to define a single argument_type.
The aim is to use MyPredicate as argument to range adaptors, with a readable syntax like this:
using boost::for_each;
using boost::adaptors::filtered;
list<T1> list1;
list<T2> list2;
for_each(list1 | filtered(!MyPredicate()), doThis);
for_each(list2 | filtered(!MyPredicate()), doThat);
Of course, any solution involving explicit disambiguation is of no interest here.
Thank you in advance.
[ACCEPTED SOLUTION]
I'm using a slightly modified version of Angew's solution:
template <class Predicate>
struct Not
{
Predicate pred;
Not(Predicate pred) : pred(pred) {}
template <class tArg>
bool operator() (const tArg &arg) const
{ return !pred(arg); }
};
template <class Pred>
inline Not<Pred> operator! (const Pred &pred)
{
return Not<Pred>(pred);
}
template <class Pred>
Pred operator! (const Not<Pred> &pred)
{
return pred.pred;
}
Note that operators && and || can benefit from this trick likewise.
You can do this:
struct MyPredicate
{
bool positive;
MyPredicate() : positive(true) {}
bool operator() (T1) const {
return original_return_value == positive;
}
bool operator() (T2) const {
return original_return_value == positive;
}
};
inline MyPredicate operator! (MyPredicate p) {
p.positive = !p.positive;
return p;
}
To address your concern of forgetting to use positive, you could try an alternative approach with a wrapper class.
template <class Predicate>
struct NegatablePredicate
{
Predicate pred;
bool positive;
NegatablePredicate(Predicate pred, bool positive) : pred(pred), positive(positive) {}
template <class tArg>
bool operator() (const tArg &arg) const
{ return pred(arg) == positive; }
};
template <class Pred>
inline NegatablePredicate<Pred> operator! (const Pred &pred)
{
return NegatablePredicate<Pred>(pred, false);
}
You can also add an overload for optimisation purposes:
template <class Pred>
inline NegatablePredicate<Pred> operator! (const NegatablePredicate<Pred> &pred)
{
return NegatablePredicate<Pred>(pred.pred, !pred.positive);
}
To address possible concern with the wide scope of the template operator!, you can employ boost::enable_if magic.
You actually can derive from std::unary_function:
template<typename T>
struct MyPredicate : std::unary_function<T, bool>
{
bool operator()(T) const;
};
Hy there,
I'm trying to adapt an existing code to boost::variant. The idea is to use boost::variant for a heterogeneous vector. The problem is that the rest of the code use iterators to access the elements of the vector. Is there a way to use the boost::variant with iterators?
I've tried
typedef boost::variant<Foo, Bar> Variant;
std::vector<Variant> bag;
std::vector<Variant>::iterator it;
for(it= bag.begin(); it != bag.end(); ++it){
cout<<(*it)<<endl;
}
But it didn't work.
EDIT: Thank you for your help! But in my design, I need to get one element from the list and pass it around other parts of the code (and that can be nasty, as I'm using GSL). The idea of using an iterator is that I can pass the iterator to a function, and the function will operate on the return data from that specific element. I can't see how to do that using for_each. I need to do something similar to that:
for(it=list.begin(); it!=list.end();++it) {
for(it_2=list.begin(); it_2!=list.end();++it_2) {
if(it->property() != it_2->property()) {
result = operate(it,it_2);
}
}
}
Thanks!
Well of course there is. Dereferencing the iterators will naturally yield a boost::variant<...> reference or const-reference.
However it does mean that the rest of code should be variant-aware. And notably use the boost::static_visitor to execute operations on the variants.
EDIT:
Easy!
struct Printer: boost::static_visitor<>
{
template <class T>
void operator()(T const& t) const { std::cout << t << std::endl; }
};
std::for_each(bag.begin(), bag.end(), boost::apply_visitor(Printer());
Note how writing a visitor automatically yields a predicate for STL algorithms, miam!
Now, for the issue of the return value:
class WithReturn: boost::static_visitor<>
{
public:
WithReturn(int& result): mResult(result) {}
void operator()(Foo const& f) const { mResult += f.suprise(); }
void operator()(Bar const& b) const { mResult += b.another(); }
private:
int& mResult;
};
int result;
std::for_each(bag.begin(), bag.end(), boost::apply_visitor(WithReturn(result)));
EDIT 2:
It's easy, but indeed need a bit of coaching :)
First, we remark there are 2 different operations: != and operate
struct PropertyCompare: boost::static_visitor<bool>
{
template <class T, class U>
bool operator()(T const& lhs, U const& rhs)
{
return lhs.property() == rhs.property();
}
};
struct Operate: boost::static_visitor<result_type>
{
result_type operator()(Foo const& lhs, Foo const& rhs);
result_type operator()(Foo const& lhs, Bar const& rhs);
result_type operator()(Bar const& lhs, Bar const& rhs);
result_type operator()(Bar const& lhs, Foo const& rhs);
};
for(it=list.begin(); it!=list.end();++it) {
for(it_2=list.begin(); it_2!=list.end();++it_2) {
if( !boost::apply_visitor(PropertyCompare(), *it, *it_2) ) {
result = boost::apply_visitor(Operate(), *it, *it_2));
}
}
}
For each is not that good here, because of this if. It would work if you could somehow factor the if in operate though.
Also note that I pass not iterators but references.