How can I ensure iterator doesn't go out of range vector? and in the case where the filter would not match any elements of the input; in that case, how can i ensure ensure that begin() is equal to end()
Code
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; }
};
struct FilteringIterator : Iterator {
Callable callable;
using OriginalIterator = Iterator;
Iterator end;
Iterator current=(Iterator &)*this;;
FilteringIterator(const Iterator begin, Iterator end, Callable callable):Iterator(begin),end(end),callable(callable){}
Iterator &get_orig_iter() { return ((Iterator &)*this); }
auto operator++(){ return ((Iterator &)*this)++;}
bool operator==(const Iterator& rhs) const { return ((Iterator &)*this) == rhs; }
bool operator!=(const Iterator& rhs) const { return !(operator==(rhs)); }
auto operator*() {
while ((Iterator &)*this!=end && !callable(*get_orig_iter()))
++(Iterator &)*this;
return *(Iterator &)*this;
}
};
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>;
auto t=filter_iterator{container.end(),container.end(),action};
return Range{filter_iterator{container.begin(),container.end(),action}, filter_iterator{container.end(),container.end(),action}};
};
};
Main
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
for(auto a : v | filter(less_then(15))) // filter is applied lazily as the range is traversed
std::cout << a <<"D" << std::endl;
// prints 17.5 and 22.5 to the console
Output
2.5
7.5
12.5
Error
Move while loop to operator!=and return false if begin() is equal to end() to exist for loop
Related
I have implemented a (non-const) random access iterator for my custom container class by inheriting from the very basic std::iterator template class (see below). All that was required to do this was to pass in the required types.
I have not been able to find much information on how to set up a reverse iterator, but I'm pretty sure there's a method where I can use the existing iterator with a few new typedefs and define rbegin() and rend(). And that's where I'm stuck. Could someone help?
template <class T, class A = std::allocator<T>>
class ring {
public:
typedef ring<T, A> self_type;
typedef T value_type;
typedef A alloc_type;
typedef ptrdiff_t size_type;
typedef typename alloc_type::difference_type difference_type;
typedef typename alloc_type::pointer pointer;
typedef typename alloc_type::reference reference;
typedef typename alloc_type::const_pointer const_pointer;
typedef typename alloc_type::const_reference const_reference;
class iterator; // we implement iterator as nested class, so no need to typedef it
iterator begin() { return iterator(this, 0); }
iterator end() { return iterator(this, size()); } // the current size (which is one past the end of the array)
class iterator : public std::iterator<std::random_access_iterator_tag, value_type, difference_type, pointer, reference> {
private:
self_type *ring_; // typedefs defined in ring class apply here
size_type offset_;
public:
iterator(self_type *r, size_type o) : ring_{r}, offset_{o} {}
reference operator* () const { return (*ring_)[offset_]; }
pointer operator-> () const { return &(operator*()); }
iterator& operator++ () {
++offset_;
return *this;
}
friend bool operator== (const iterator& it1, const iterator& it2) { return ((it1.ring_ == it2.ring_ && it1.offset_ == it2.offset_)); }
friend bool operator!= (const iterator& it1, const iterator& it2) { return (!(it1 == it2)); }
iterator& operator-- () {
--offset_;
return *this;
}
iterator operator++ (int) {
iterator clone(*this); // make a duplicate
++offset_;
return clone; // return the duplicate
}
iterator operator-- (int) { // has to be return by value
iterator clone(*this);
--offset_;
return clone;
}
iterator& operator+=(size_type n) {
offset_ += n;
return *this;
}
iterator& operator-=(size_type n) {
offset_ -= n;
return *this;
}
...
reference operator[] (size_type n) const { return (*ring_)[n]; }
};
};
You need to define the reverse_iterator type alias and the rbegin and rend methods. The reverse iterator should be implemented with std::reverse_iterator (defined in header <iterator>)
using reverse_iterator = std::reverse_iterator< iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
reverse_iterator rbegin() { return end (); }
const_reverse_iterator rbegin() const { return end (); }
reverse_iterator rend () { return begin(); }
const_reverse_iterator rend () const { return begin(); }
const_reverse_iterator crbegin() const { return rbegin(); }
const_reverse_iterator crend () const { return rend (); }
And that's everything. No magic.
Let me start by giving you a basic associative-array implementation.
#include <utility>
#include <functional>
#include <vector>
#include <algorithm>
#include <iostream>
namespace chops {
template <typename Key, typename Value,
typename Compare = std::less<Key>>
struct map {
using value_type = std::pair<const Key, Value>;
using key_type = Key;
using mapped_type = Value;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using key_compare = Compare;
using reference = value_type&;
using const_reference = value_type const&;
using iterator = typename std::vector<value_type>::iterator;
using const_iterator = typename std::vector<value_type>::const_iterator;
iterator begin() {
return data.begin();
}
iterator end() {
return data.end();
}
const_iterator begin() const {
return data.begin();
}
const_iterator end() const {
return data.end();
}
const_iterator cbegin() const {
return data.cbegin();
}
const_iterator cend() const {
return data.cend();
}
size_type size() {
return data.size();
}
bool empty() {
return data.empty();
}
void clear() {
data.clear();
}
mapped_type& operator[](Key const& k) {
key_comp kc{k};
iterator it = std::find_if(begin(), end(), kc);
if(it == end()) {
auto n = std::make_pair(k, mapped_type{});
data.push_back(n);
return data.back().second;
} else
return (*it).second;
}
template< class... Args >
std::pair<iterator,bool> emplace(Args&&... args) {
value_type v{std::forward<Args>(args)...};
key_comp kc{v.first};
iterator it = std::find_if(begin(), end(), kc);
if(it == end()) {
data.push_back(v);
return std::make_pair(data.end()--, true);
} else
return std::make_pair(it, false);
}
void erase(iterator pos){
data.erase(pos);
}
private:
struct key_comp {
Key k;
bool operator()(value_type const& p1) {
return p1.first == k;
}
};
std::vector<value_type> data;
};
}
int main() {
chops::map<int, std::string> m1;
m1[1] = "Burak";
m1.emplace(2, "Kaan");
m1.emplace(3, "Copur");
for (auto& kv : m1)
std::cout << kv.first << " has value " << kv.second << std::endl;
m1.erase(m1.begin());
for (auto& kv : m1)
std::cout << kv.first << " has value " << kv.second << std::endl;
}
First, the code uses vector to store key-value pairs. This makes implementation easy but operations are not O(log(n)) like balanced-tree implementations or O(1) like hashing-based implementations. In fact, this is a container of containers in a sense and the outer container may be parametrized in an implementation. Anyways, my problem is about that erase function, which I just delegate to erase function of underlying vector. Compiler tells me that copy constructor is removed from the pair type, since it has a user-defined move. Erase tries to copy the parts after the erase place I guess, and tries to use copy-constructor there.
The thing is, I devised a minimal example as follows:
#include <vector>
#include <string>
#include <utility>
int main() {
auto p1 = std::make_pair(1, "Burak");
auto p2 = std::make_pair(2, "Kaan");
std::vector<std::pair<int, std::string>> v1;
v1.push_back(p1);
v1.push_back(p2);
v1.erase(v1.begin());
}
where I can easily erase from vectors. So, what might be not working in my erase implementation?
I am trying to write an iterator adaptor that should call a member function (or access a member of the object) each time it is dereferenced. Here is an example of such an API:
vector<pair<int,int>> ps = {{1,"a"}, {2,"b"}, {3,"c"}};
// Pairs that represent ranges
auto rf = make_adaptor(ps.begin(), ps.end(), [](const auto& x) {return x.first;}
auto rs = make_adaptor(ps.begin(), ps.end(), [](auto& x) {return x.second;}
Should print out 123:
for_each(rf.first, rf.second, [](const auto& x){std::cout << x;});
Should set every second element of the pairs in ps:
for_each(rs.first, rs.second, [](auto& x){ x = "hello";});
I have tried writing an own iterator type together with a make_adaptor method, but I can't seem to get it to work:
template <typename Iterator, typename UnaryOp>
struct adaptor {
using value_type = std::result_of<UnaryOp(typename Iterator::reference)>::type;
using reference = value_type&;
using pointer = value_type*;
using difference_type = typename Iterator::difference_type;
using iterator_category = typename Iterator::iterator_category;
adaptor(){};
adaptor(Iterator it, UnaryOp func) : _it(it), _func(func) {}
reference operator*() const { return _func(*_it); }
pointer operator->() const { return &_func(*_it); }
bool operator==(const adaptor& other) const { return _it == other._it; }
bool operator!=(const adaptor& other) const { return _it != other._it; }
adaptor& operator++() {
++_it;
return *this;
}
Iterator _it;
UnaryOp _func;
};
template <typename Iterator, typename UnaryOp>
auto make_adaptor(Iterator first, Iterator last, UnaryOp func) {
return std::make_pair(adaptor<Iterator, UnaryOp>(first, func),
adaptor<Iterator, UnaryOp>(last, func));
};
The reason for this is the following: Let's say I have an algorithm convex_hull which works on points. But now I have objects which contains points as a member (struct A { points pos;};). I want to call convex_hull on a collection of As.
With range-v3, you may do something similar to:
const std::vector<std::pair<int,const char*>> ps = {{1,"a"}, {2,"b"}, {3,"c"}};
for (const auto s : ps | ranges::view::keys)
{
std::cout << " " << s;
}
for (const auto s : ps | ranges::view::transform([](const auto& p) { return p.first;} ))
{
std::cout << " " << s;
}
Demo
I have some templates which can either have a map or a vector as underlying container. I would like the template to be able to expose const iterators to the elements. Most information I have read on how to expose iterators (such as this accu article) uses a form of
typedef std::vector<int>::iterator iterator;
typedef std::vector<int>::const_iterator const_iterator;
iterator begin() { return values.begin(); }
iterator end() { return values.end(); }
That doesn't really work for the template that uses the map though, because to access elements, the template can't use it->SomeMemberFunc() anymore, but rather needs to use it->second.SomeMemberFunc(). So I am looking to expose an iterator to the map elements which doesn't give access to the keys but only the values of the map.
How would I accomplish this?
A workaround1
#include <map>
#include <iterator>
template <typename Iter>
struct map_iterator : public std::iterator<std::bidirectional_iterator_tag,
typename Iter::value_type::second_type>
{
map_iterator() {}
map_iterator(Iter j) : i(j) {}
map_iterator& operator++() { ++i; return *this; }
map_iterator& operator--() { --i; return *this; }
bool operator==(map_iterator j) const { return i == j.i; }
bool operator!=(map_iterator j) const { return !(*this == j); }
typename map_iterator::reference operator*() { return i->second; }
typename map_iterator::pointer operator->() { return &i->second; }
map_iterator operator--(int) { return std::prev(--(*this)); }
map_iterator operator++(int) { return std::next((++*this)); }
protected:
Iter i;
};
template <typename Iter>
inline map_iterator<Iter> make_map_iterator(Iter j) {
return map_iterator<Iter>(j);
}
And then
int main() {
std::map<int,std::string> m {{1, "Hi"},{2, "Bye"}};
for (auto i=make_map_iterator(m.begin()); i!=make_map_iterator(m.end());i++)
cout << *i << endl;
}
Live code.
I have a custom read-only data structure that I need to transverse. I would like to create a custom iterator that need to skip certain values.
A simple but equivalent example would be the following. I have a vector of numbers and I want to loop through all skipping the negative values. Normally I would do something like:
vector<int> v;
for (vector<int>::iterator it = v.begin(); it!=v.end(); ++it) {
if (*it > 0) {
dosomething(*it);
}
}
But I would like to do something like:
vector<int> v;
for (vector<int>::my_iterator it = v.my_begin(); it!=v.my_end(); ++it) {
dosomething(*it);
}
What is the right way to achieve this?
This is easily achieved with a boost::filter_iterator, if your data structure already stores a container under the hood. Here's a simple example:
#include <vector>
#include <iostream>
#include <boost/iterator/filter_iterator.hpp>
class X{
typedef std::vector<int> container;
struct Pred{
bool operator()(int i){
return i % 2 == 0;
}
};
public:
typedef boost::filter_iterator<Pred, container::iterator> iterator;
void add(int val){ nums.push_back(val); }
iterator begin(){ return iterator(nums.begin(), nums.end()); }
iterator end(){ return iterator(nums.end(), nums.end()); }
private:
container nums;
};
int main(){
X x;
for(int i=0; i < 10; ++i)
x.add(i);
for(X::iterator it = x.begin(), ite = x.end(); it != ite; ++it)
std::cout << *it << ' ';
}
Live example at Ideone. Output:
0 2 4 6 8
This isn't a very nice solution, but I'll post it anyway. Any attempt to dereference this iterator wrapper will cause it to check the current value and advance the iterator past any negative values. It will be called recur
template<typename InputIterator>
struct nonnegative_iterator : InputIterator {
template<typename Arg>
nonnegative_iterator(Arg i) : InputIterator(i) {
}
typename InputIterator :: reference operator* () {
typename InputIterator :: reference x = InputIterator :: operator*();
if( x < 0) {
++ (*this); // equivalent to this -> operator++ ()
return **this;
} else
return x;
}
};
which can be used like this:
for ( nonnegative_iterator< vector<int>::iterator > it = v.begin(); it!=v.end(); ++it) {
This has some problems, for example I haven't implemented a const method to allow to dereference to value_type. So use at your own risk!
Assuming you don't have control over the interface of vector<int>, e.g. because it is actually std::vector<int>, the first thing you want to do is to change the way you get your custom iterators. That is, instead of writing
for (vector<int>::my_iterator it = v.my_begin(); it != v.my_ned(); ++it)
you would use
for (my_iterator it(my_begin(v)), end(my_end(v)); it != end; ++it)
You can achieve the modified interface for a custom container but this is a bigger fish to fry. Creating your input iterator now essentially amounts to creating a suitable wrapper for the underlying iterator. This could look something like this:
template <typename InIt, Pred>
struct my_iterator {
typedef typename std::iterator_traits<InIt>::value_type value_type;
typedef typename std::iterator_traits<InIt>::difference_type difference_type;
typedef typename std::iterator_traits<InIt>::reference reference;
typedef typename std::iterator_traits<InIt>::pointer pointer;
my_iterator(InIt it, InIt end, Pred pred): it_(it), end_(end), pred_(pred) {}
bool operator== (my_iterator const& other) const { reutrn this->it_ == other.it_; }
bool operator!= (my_iterator const& other) const { return !(*this == other); }
reference operator*() { return *this->it_; }
pointer operator->() { return this->it_; }
my_iterator& operator++() {
this->it_ = std::find_if(this->it_, this->end_, this->pred_);
return *this;
}
my_iterator operator++(int)
{ my_iterator rc(*this); this->operator++(); return rc; }
private:
InIt it_, end_;
Pred pred_;
The my_begin() and my_end() functions would then create a suitable object of this type. One approach to avoid having to write this is to have a look a Boost's iterator adaptors: there should be something suitable over there.