From this old question
C++ custom collection reverse_iterator with similar behaviour to std::vector implementation
I thought that the lines (after revising his design a bit)
template <typename Iterator>
class reverse_iterator {
Iterator _it;
public:
reverse_iterator(const Iterator& it):_it(it) { }
Iterator base() const {Iterator it = _it; return --it;}
typename Iterator::value_type& operator*() const {return *base();}
// ...
};
were correct (no one replied that they were incorrect). But it doesn't give the same output that this test with std::reverse_iterator gives:
#include <iostream>
#include <iterator>
#include <vector>
int main () {
std::vector<int> myvector = {1,2,3};
std::vector<int>::iterator it = std::next(myvector.begin());
std::reverse_iterator<std::vector<int>::iterator> r(it);
std::cout << *it << '\n'; // 2
std::cout << *r << '\n'; // 1
std::cout << *r.base() << '\n'; // 2
}
which seems to show that the lines should instead be
template <typename Iterator>
class reverse_iterator {
Iterator _it;
public:
reverse_iterator(const Iterator& it):_it(it) { }
Iterator base() const { return _it; }
typename Iterator::value_type& operator*() const { return *--base(); }
// ...
};
which would indeed give the same output as with std::reverse_iterator. What is correct here?
Related
I would like to find a clean way to slightly change the way std::vector operates.
Problem background
I need to be able to have index in the vector where the pointer would essentially slip one back, so for example; if my vector contains {0,1,2,3,4,5} and index [3] needs to slip, when iterating through the vector it should return: 0, 1, 2, 3, 3, 4, 5
Problem
Without rewriting the entire vector class and implementing my changes, is it possible to inherit std::vector<T> into a custom class, and override the behavior of the iterators ++ operator as well as the vector::begin()? (to add memory of the fact that it has already slipped one and not to slip again)
What I have tried
I have tried a basically implementation so far, but have gotten stuck when trying to override the begin() function.
#include <vector>
#include <iostream>
#include <iterator>
template <typename T>
class myVector : public std::vector<T>{
public:
class myIterator : public std::vector<T>::iterator
{
// call vector's iterotor constructor
//override
// iterator& operator++(void){}
// iterator operator++(int){}
};
using std::vector<T>::vector; // use the constructor from vector
// extend the begin function, but include original operation
myVector::myIterator begin() const
{
std::cout << "hi\n"; // testing to see if begin has been overriden properly
return std::vector<T>::begin();
}
};
// print out the vector
template <typename T>
std::ostream& operator<<(std::ostream& os, const myVector<T>& v)
{
auto begin=v.begin();
while (begin!=v.end())
{
os << *begin;
++begin;
if(begin!=v.end())
{
os << ',';
}
}
return os;
}
int main() {
myVector<int> vec = {1,2,3,4};
std::cout << vec << '\n';
}
If you have an alternative clean solutions, it is also welcome.
Thanks
I would never inherit from std::vector publicly. It is just too easy to be used wrong and you have no control over misuse. std::vector has no virtual destructor!
Iterators seems to be the appropriate customization point. Much more is needed to get a fully compliant iterator, but this is enough for a working example:
#include <iterator>
#include <vector>
#include <iostream>
template <typename It>
struct slippery_iterator {
bool slipped = false;
It to_be_repeated;
It iterator;
slippery_iterator(It iterator,It to_be_repeated) : iterator(iterator),to_be_repeated(to_be_repeated){}
slippery_iterator& operator++(){
if (!slipped && iterator == to_be_repeated){
slipped = true;
return *this;
}
++iterator;
return *this;
}
typename std::iterator_traits<It>::reference operator*(){
return *iterator;
}
bool operator!=(It other) { return iterator != other;}
};
template <typename It>
slippery_iterator<It> make_slippery_iterator(It it,It slip){
return {it,slip};
}
int main() {
std::vector<int> x{1,2,3,4,5};
auto begin = make_slippery_iterator(x.begin(),x.begin()+2);
for (; begin != x.end(); ++begin){
std::cout << *begin;
}
}
Output:
123345
PS: Note that I am used to C++11 where you need a make_x helper. It isnt needed with more recent standards.
As others already said, just define a custom iterator. If you moreover want the nice range iteration, you can then just define a custom range class returning your custom iterators.
See a working example below (needs --std=c++17):
#include <vector>
#include <iostream>
template<typename T>
class SlipIterator {
private:
using iterator = typename std::vector<T>::const_iterator;
iterator i;
iterator slip;
bool has_slipped;
public:
SlipIterator(iterator i, iterator slip): i(i), slip(slip), has_slipped(false) {}
SlipIterator &operator++() {
if ((!has_slipped) && (i == slip))
has_slipped = true;
else
++i;
return *this;
}
bool operator!=(SlipIterator<T> &the_end) const { return i != the_end.i; }
const T &operator*() const { return *i; }
};
template<typename T>
class SlipperyRange {
private:
const std::vector<T> &v;
size_t slip_index;
public:
SlipperyRange(const std::vector<T> &v, size_t slip_index) : v(v), slip_index(slip_index) {}
SlipIterator<T> begin() const { return SlipIterator<T>(v.cbegin(), v.cbegin() + slip_index); }
SlipIterator<T> end() const { return SlipIterator<T>(v.cend(), v.cend()); }
};
int main() {
std::vector<int> v{1,2,3,4,5};
for(const int i: SlipperyRange{v, 2})
std::cout << i << ' ';
std::cout << '\n';
return 0;
}
I'm having some trouble creating an iterator type for my class which can be used to initialize a vector. Probably best explained with some code, here's an example of what my implementation looks like:
#include <tuple>
#include <cstdint>
struct Foo
{
public:
Foo(uint8_t i) : i(i) {}
struct iterator
{
public:
using value_type = std::pair<int, bool>;
using reference = value_type;
using pointer = value_type*;
using iterator_category = std::input_iterator_tag;
bool operator == (const iterator& other) { return cur == other.cur; }
bool operator != (const iterator& other) { return !(*this == other); }
iterator& operator ++ () { if (cur > -1) --cur; return *this; }
iterator operator ++ (int) { iterator tmp = *this; ++(*this); return tmp; }
reference operator * () { return std::make_pair<int, bool>(8 - cur, foo->i & (1 << cur)); }
pointer operator -> () { static value_type v; v = *(*this); return &v; }
private:
friend Foo;
iterator(const Foo* foo, int start) : foo(foo), cur(start) {}
const Foo* foo;
int cur;
};
iterator begin() const { return iterator(this, 7); }
iterator end() const { return iterator(this, -1); }
uint8_t i;
};
The logic of what the class is doing doesn't matter; it's the fact that although I can use this iterator in a for loop, I get an error when attempting to construct a vector from it:
#include <iostream>
#include <vector>
// struct Foo...
int main()
{
Foo foo(73);
// Works, output as expected
for (auto elem : foo)
std::cout << "Position " << elem.first << " is a " << elem.second << '\n';
// Works, output as expected
for (auto it = foo.begin(), end = foo.end(); it != end; ++it)
std::cout << "Position " << it->first << " is a " << it->second << '\n';
// Error: cannot convert argument 1 from 'PowersOf2::iterator' to 'const unsigned __int64'
std::vector<std::pair<int, bool>> v(foo.begin(), foo.end());
}
cppreference tells me that std::vector's constructor takes two iterators if InputIt satisfies InputIterator. It also tells me that the requirements for an InputIterator are
Satisfies Iterator
Satisfies EqualityComparable
i != j, *i, i->m, ++i, (void)i++ and *i++ are valid
so I'm not sure what's gone wrong. Any help appreciated!
According to cccpreference.com the std::vector constructor that takes iterators "[...] only participates in overload resolution if InputIt satisfies InputIterator, to avoid ambiguity with the overload (2).".
To satisfy InputIterator a type must satisfy Iterator. In turn, Iterator requires the type to provide several type alias, including difference_type which you've omitted.
Try adding the public type alias using difference_type = std::ptrdiff_t; to your iterator type.
This is a simplified instance of actual code. The goal was to provide access to container elements via range-based loops BUT have the elements changed on-the-fly (here ints are squared) without exposing the change.
The code works but seems overly complicated and unreadable. What simplification did I miss?
#include <vector>
#include <iostream>
using ivec_t = std::vector<int>;
class A {
ivec_t vec;
public:
A(const ivec_t& v) : vec(v) {}
class sq_class {
class iter {
ivec_t::iterator ivit;
public:
iter(ivec_t::iterator the_ivit) : ivit(the_ivit) {}
bool operator!=(const iter& other) { return ivit != other.ivit; }
iter& operator++() { ++ivit; return *this; }
int operator*() { return (*ivit)*(*ivit); } // <-------------------
};
ivec_t ivec;
public:
sq_class(ivec_t& the_ivec) : ivec(the_ivec) {}
iter begin() { return iter(ivec.begin()); }
iter end() { return iter(ivec.end()); }
};
sq_class squares() { return sq_class(vec); }
};
main()
{
A a({1,2,4});
// expected output: 1, 4, 16,
for (auto item : a.squares())
std::cerr << item << ", ";
std::cerr << "\n";
}
This code is adopted from the boost multi-index "mru" example:
http://www.boost.org/doc/libs/1_46_1/libs/multi_index/example/serialization.cpp
I have code that is doing something similiar as a boost::unordered_map, but I would really like to add the mru functionality from this example.
I would like to make this code work as close to having a boost::unordered_map as possible. The key feature for me is the [] operator of the unordered_map.
The final lines of main() are broken and above each line as a comment is my question.
Thanks in advance to all answers comments.
#include <algorithm>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <iostream>
using namespace boost::multi_index;
class my_struct {
public:
my_struct(int in_a, std::string in_b) : a(in_a), b(in_b) {}
int a;
std::string b;
bool operator==(const my_struct &rhs) const
{
return (a == rhs.a);
}
bool operator!=(const my_struct &rhs) const
{
return !(*this == rhs);
}
friend std::ostream& operator<<(std::ostream &out, const my_struct&ms);
};
std::ostream& operator<<(std::ostream &out, my_struct &ms)
{
out << ms.a << " " << ms.b << std::endl;
return out;
}
inline std::size_t
hash_value(const my_struct &val)
{
return boost::hash_value(val.a);
}
// tags for multi_index
struct umap {};
template <typename Item>
class mru_list
{
typedef multi_index_container<
Item,
indexed_by<
sequenced<>,
hashed_unique<boost::multi_index::tag<umap>, identity<Item> >
>
> item_list;
public:
typedef Item item_type;
typedef typename item_list::iterator iterator;
mru_list(std::size_t max_num_items_):max_num_items(max_num_items_){}
void insert(const item_type& item)
{
std::pair<iterator,bool> p=il.push_front(item);
if(!p.second){ /* duplicate item */
il.relocate(il.begin(),p.first); /* put in front */
}
else if(il.size()>max_num_items){ /* keep the length <= max_num_items */
il.pop_back();
}
}
iterator begin(){return il.begin();}
iterator end(){return il.end();}
//private:
item_list il;
std::size_t max_num_items;
};
int main()
{
mru_list<my_struct> mru(10);
my_struct one(1, "One");
mru.insert(one);
mru.insert(my_struct(2, "Two"));
mru.insert(my_struct(3, "Three"));
mru.insert(one);
std::cout<<"most recently entered terms:"<<std::endl;
for (mru_list<my_struct>::iterator itr = mru.begin(); itr != mru.end(); ++itr) {
std::cout << itr->a << std::endl;
}
// what is my return type?
mru.il.get<umap>();
// Why doesn't this work?
mru_list<my_struct>::iterator itr = mru.il.get<umap>().find(one);
// Why doesn't this have a [] operator like boost:unordered_map
mru.il.get<umap>()[1] = "foobar";
return 0;
}
// what is my return type?
mru.il.get<umap>();
Its return type is the type of your umap index, which is:
typedef typename boost::multi_index::index<
item_list
, umap
>::type hashed_index_t;
mru_list<my_struct>::hashed_index_t& hashed_index = mru.il.get<umap>();
In C++11 it is easier with auto:
auto& hashed_index = mru.il.get<umap>();
// Why doesn't this work?
mru_list<my_struct>::iterator itr = mru.il.get<umap>().find(one);
find() returns an iterator of umap (second) index and the above statement is assigning it to the iterator of the first index. There are projection operations to convert from one index iterator type to another iterator type of the same multi-index container, e.g.:
mru_list<my_struct>::iterator itr = project<0>(mru.il, hashed_index.find(one));
// Why doesn't this have a [] operator like boost:unordered_map
Can't say why, it just doesn't.
I have a class Foo that contains a map and provides begin() and end() functions to iterate over it:
class Foo {
typedef std::map<int, double> Container;
typedef Container::const_iterator const_iterator;
Container c_;
public:
const_iterator begin() const { return c_.begin(); }
const_iterator end() const { return c_.end(); }
void insert(int i, double d) { c_[i] = d; }
// ...
};
Now I would like to change it internally from std::map<int, double> to just a std::set<int>, but I don't want to break any client code.
So the double d in the insert function would now just be ignored. And the following code should still be valid, where it->second will now just always be 0.0:
Foo foo;
for(Foo::const_iterator it = foo.begin(); it != foo.end(); ++it) {
std::cout << it->first << " " << it->second << std::endl;
}
How can I make these changes in the Foo class?
In other words, how can I provide a Foo::const_iterator that adapts the new internal std::set<int>::const_iterator to behave like the old std::map<int,double>::const_iterator?
UPDATE: The reason I want to get rid of the map is memory efficiency. I have millions of Foo instances and cannot afford to store the double values in them.
Would using
std::set<std::pair<int, double> >
not be sufficient for this comparability?
Failing that you can always write your own iterator which wraps the std::list iterator and provides first and second members. Basically your operator++ would call operator++ on the real iterator etc. and the de-referencing operator could return either a temporary std::pair (by value) or a reference to a std::pair that lives within the iterator itself (if your legacy code can deal with that).
Update, slightly contrived example, might work depending on your scenario:
#include <iostream>
#include <set>
class Foo {
typedef std::set<int> Container;
typedef Container::const_iterator legacy_iterator;
Container c_;
// legacy iterator doesn't have a virtual destructor (probably?), shouldn't
// be a problem for sane usage though
class compat_iterator : public legacy_iterator {
public:
compat_iterator(const legacy_iterator& it) : legacy_iterator(it) {
}
const std::pair<int,double> *operator->() const {
static std::pair<int,double> value;
value = std::make_pair(**this, 0.0);
// Not meeting the usual semantics!
return &value;
}
};
public:
typedef compat_iterator const_iterator;
const_iterator begin() const { return c_.begin(); }
const_iterator end() const { return c_.end(); }
};
int main() {
Foo foo;
for(Foo::const_iterator it = foo.begin(); it != foo.end(); ++it) {
std::cout << it->first << " " << it->second << std::endl;
}
}
How about something like this?
#include <iostream>
#include <map>
#include <set>
struct Funky
{
int first;
static const double second;
Funky(int i)
: first(i)
{}
};
const double Funky::second = 0.0;
bool operator<(const Funky& lhs, const Funky& rhs)
{
return lhs.first < rhs.first;
}
class Foo
{
private:
//std::map<int,double> m_data;
std::set<Funky> m_data;
public:
//typedef std::map<int,double>::const_iterator const_iterator;
typedef std::set<Funky>::const_iterator const_iterator;
const_iterator begin() const
{
return m_data.begin();
}
const_iterator end() const
{
return m_data.end();
}
void insert(int i, double d)
{
//m_data.insert(std::make_pair(i, d));
m_data.insert(i);
}
};
int main()
{
Foo foo;
foo.insert(23, 9.0);
for(Foo::const_iterator it=foo.begin(), iend=foo.end(); it!=iend; ++it)
{
std::cout << it->first << ' ' << it->second << '\n';
}
return 0;
}
Perhaps something along the lines of
operator int()(const std::pair<int, double>& p) const {
return p.first;
}
maybe within some wrapper?
Perhaps you can define a fake_pair class that implements first and second and put a set<fake_pair> inside Foo.
You can't, not completely. The problem is you are changing your interface, which will always break your clients. I would recommend you create two new functions of newBegin and newEnd (or similar) which has your new behaviour. Your old interface you keep this the same but mark it as depreciated. The implementation of this old interface can use one of the work around described by the others.