I am trying to develop smart iterator, but even when I create a naive one it crash when I am using sort with it.
The range for loop worked well, but std::sort does not.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<typename I>
class it {
public:
it(I i) : i(i){}
using iterator_category = std::random_access_iterator_tag;
using value_type = typename I::value_type;
using difference_type = std::ptrdiff_t;
using pointer = typename I::pointer;
using reference = typename I::reference;
value_type &operator*() {
return *i;
}
it &operator++() {
++i;
return *this;
}
it &operator--() {
--i;
return *this;
}
bool operator!=(it a) {
return a.i != i;
}
it &operator+(std::size_t n) {
i += n;
return *this;
}
it &operator-(std::size_t n) {
i -= n;
return *this;
}
std::ptrdiff_t operator-(it a) {
return i - a.i;
}
bool operator==(it a) {
return a.i == i;
}
bool operator<(it a) {
return i < a.i;
}
private:
I i;
};
int main()
{
std::vector<int> v = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
for(auto e : v)
std::cout << e << " ";
std::cout << std::endl;
std::sort(it<decltype(v.begin())>(v.begin()), it<decltype(v.end())>(v.end()));
for(auto e : v)
std::cout << e << " ";
std::cout << std::endl;
return 0;
}
The crash happen in "clang-code" here (gdb tell me that) :
struct _Iter_less_iter
{
template<typename _Iterator1, typename _Iterator2>
_GLIBCXX14_CONSTEXPR
bool
operator()(_Iterator1 __it1, _Iterator2 __it2) const
{ return *__it1 < *__it2; }
};
It happened when it deferrence it.
Do you have an idea?
Don't know for sure what the underlying problem is, but this is definitely wrong:
it &operator+(std::size_t n) {
i += n;
return *this;
}
That operator should return a new iterator, and not modify the one it's called on. Something like this:
it operator+(std::size_t n) {
it temp = *this;
temp.i += n;
return temp;
}
Note that this returns the iterator by value, not by reference.
Same thing for operator-.
Your operator+ has the semantics of operator+=, and your operator- has the semantics of operator-=. They should not modify the iterator, but instead create a new iterator with the modified value and return that. Also, they should both accept signed values. In fact, a proper random access iterator should have both sets of operators, so just keep the functions as they are, but change the signatures.
it& operator+=(difference_type n) {
i += n;
return *this;
}
it &operator-=(difference_type n) {
i -= n;
return *this;
}
Then you can implement operator+ and operator- in terms of those. (note that these return by value, not reference, and are marked const)
it operator+(difference_type n) const {
it result = *this;
result += n;
return result;
}
it operator-(difference_type n) const {
it result = *this;
result -= n;
return result;
}
Related
I am trying to use <ranges> (C++20 MSVC) to iterate a custom container called Span, whose begin/end() methods return a SpanIter. However, the following static assert fails in the test() method and the pipe operator is unrecognized with my class (but not vector<>).
static_assert(std::ranges::range<Span>, "Is not a range");
I think the method signatures match this working example. I haven't been able to track down what's missing, whether a method or typedef/using.
#include <ranges>
#include <iostream>
#include <vector>
namespace ptest {
class SpanIter;
struct Span;
struct Span : std::ranges::view_base
{
using iterator = SpanIter;
using sentinel = SpanIter;
int start;
int length;
int index;
Span() noexcept { start = length = index = 0; }
Span(int s, int l, int i) noexcept : start(l), length(l), index(i) { }
Span(const Span& other) noexcept : Span(other.start, other.length, other.index) { }
Span(const Span&& other) noexcept : Span(other.start, other.length, other.index) { }
Span& operator=(const Span& other) { start = other.start; length = other.length; index = other.index; }
bool operator==(const Span& other) const { return start == other.start && length == other.length && index == other.index; }
iterator begin();
sentinel end();
iterator cbegin() const;
sentinel cend() const;
size_t size() { return length; }
void Print() {
// eg. "range[5 - 9]: 5"
std::cout << "range [" << start << "-"
<< (start + length - 1)
<< "]: " << index << std::endl;
}
auto operator <=> (const Span& other) const = default;
};
class SpanIter {
Span Empty;
using value_type = Span;
using reference = Span&;
using const_reference = const Span&;
using iterator = SpanIter;
using sentinel = SpanIter;
using const_iterator = const SpanIter;
using iterator_category = std::forward_iterator_tag;
using difference_type = ptrdiff_t;
using pointer = Span*;
using size_type = size_t;
public:
SpanIter() noexcept { }
SpanIter(const SpanIter& other) noexcept : current_(other.current_) { }
SpanIter(const SpanIter&& other) noexcept : current_(other.current_) { }
SpanIter(Span t) noexcept : current_(t) {
current_.index = current_.start;
}
~SpanIter() { }
SpanIter& operator++() {
if (current_.index < current_.start + current_.length)
++current_.index;
return *this;
}
SpanIter operator++(int) {
SpanIter result = *this;
++(*this);
return result;
}
SpanIter& operator = (const SpanIter& other)
{
current_ = other.current_;
return *this;
}
bool operator==(const SpanIter& other) const {
return this->operator*() == *other;
}
bool operator!=(const SpanIter& other) const {
return !(*this == other);
}
template<typename T>
bool operator==(T&& value) const {
return this->operator*() == std::forward<T>(value);
}
template<typename T>
bool operator!=(T&& value) const {
return !(*this == value);
}
Span& operator*() {
return current_.start <= current_.index &&
current_.index < current_.start + current_.length
? current_
: Empty;
}
const Span& operator*() const {
return current_.start <= current_.index &&
current_.index < current_.start + current_.length
? current_
: Empty;
}
private:
Span current_;
};
SpanIter Span::begin() { return SpanIter(*this); }
Span::sentinel Span::end() { return SpanIter(Span()); }
SpanIter Span::cbegin() const { return SpanIter(*this); }
Span::sentinel Span::cend() const { return SpanIter(Span()); }
SpanIter begin(const Span& span) { return span.cbegin(); }
Span::sentinel end(const Span& span) { return span.cbegin(); }
void test() {
// WORKS (confirm pipes work with vector)
// output: 5 6
std::vector<int> v { 5, 6, 7, 8, 9};
auto works = v | std::views::take(2);
for (int i : works)
std::cout << i << " ";
// FAILS !!!!!!!!!!!!!!!!!!!
// <ranges> doesn't recognize my Span container as a range
static_assert(std::ranges::range<Span>, "Is not a range");
// FAILS !!!!!!!!!!!!!!!!!!!
// binary '|': 'Span' does not define this operator or a conversion
// to a type acceptable to the predefined operator
Span span(6, 5, 8);
auto fails = span | std::views::take(2);
// WORKS: confirm my Span operates as a container with normal C++ 11 features
// output:
// range[5 - 9] : 5
// range[5 - 9] : 6
// range[5 - 9] : 7
// range[5 - 9] : 8
// range[5 - 9] : 9
for (Span s : span)
s.Print();
}
}
The problem was that using statements for iterator traits need to be public ... that's it. This is surely obvious to most people familiar with C++, but may help other relative newbies like myself.
I need a function to add values to v[i] using the operator+
the vector v contains the values 10,2 and 3.
#include <iostream>
#include <vector>
template<typename T>
class Measurement
{
private:
T val;
public:
Measurement(T a)
: val{ a }
{}
T value() const { return val; }
Measurement<T>& operator+(const T& nr)
{
//... ???
return *this;
}
};
int main()
{
//create a vector with values (10,2,3)
std::vector<Measurement<int>> v{ 10,2,3 };
v[2] + 3 + 2; //add at v[2] value 5
for (const auto& m : v) std::cout << m.value() << ",";
return 0;
}
The result must be 10,2,8
Just add the val of the instance to other nr
Measurement<T>& operator+(const T& nr)
{
this->val += nr;
return *this;
}
However, overloading the operator+ for this might be misleading and should be avoiding such. Therefore I would suggest the traditional way
Measurement<T> operator+(const T& nr)
{
Measurement<T> tmp{ *this };
tmp.val += nr;
return tmp; // returns the temporary, which you need to reassign!
}
and do
v[2] = v[2] + 3 + 2;
for the required result.
Or even better provide operator+= which meant does return the reference to the Measurement<T>
Measurement<T>& operator+=(const T& nr)
{
this->val += nr;
return *this;
}
and call it like
v[2] += 3 + 2;
I need to build an inner class iterator to work with a container class FigureOfCircles
#define T Circle
class FigureOfCircles {
private:
Circle* c;
int size;
public:
class Iterator {
protected:
T* t;
public:
explicit Iterator (T* t1 = 0) : t(t1) { }
Iterator (const Iterator& x) : t(x.t) {}
T& operator*() const { return *t; }
T* operator->() const { return t; }
Circle& operator[](const std::size_t& n) { return t[n]; }
Iterator& operator++() { ++t; return *this; }
Iterator operator++(int) { return Iterator(t++); }
Iterator& operator--() { --t; return *this; }
Iterator operator--(int) { return Iterator(t--); }
Iterator operator- (int n) { return Iterator(t - n); }
Iterator operator+ (int n) { return Iterator(t - n); }
Iterator& operator-= (int n) { t -= n; return *this; }
Iterator& operator+= (int n) { t += n; return *this; }
bool operator== (const Iterator& x) const { return t == x.t; }
bool operator!= (const Iterator& x) const { return t != x.t; }
bool operator<= (const Iterator& x) const { return t <= x.t; }
bool operator> (const Iterator& x) const { return t > x.t; }
bool operator>= (const Iterator& x) const { return t >= x.t; }
bool operator< (const Iterator& x) const { return t < x.t; }
friend int operator- (const Iterator& x, const Iterator& y) { return x.t - y.t; }
Iterator& operator= (const Iterator& x) {
if (t == x.t) exit(-6);
t = x.t;
return *this;
}
};
FigureOfCircles (int sz) : size(sz) {
c = new T[size];
for (Iterator i = begin(); i != end(); ++i) *i = input();
}
FigureOfCircles(const FigureOfCircles& f) {
size = f.size;
c = new T[size];
for (Iterator i = begin(); i != end(); ++i) *i = f.c[i - begin()];
}
~FigureOfCircles() { if (c) delete[] c; }
Circle input() {
int size = 1;
Point* arr = new Point[size];
float r, x1, y1;
cout << endl << "Введiть к-сть точок, радiус i координати центру: ";
cin >> size >> r >> x1 >> y1;
for (int i = 0; i < size; i++) {
Point tmp;
cin >> tmp;
if (tmp.GetX() == x1 && tmp.GetY() == y1) exit(-7);
if (pow(tmp.GetX() - x1, 2) + pow(tmp.GetY() - y1, 2) != r * r) exit(-8);
arr[i] = tmp;
}
return Circle(size, r, arr, x1, y1);
}
Iterator begin() { return Iterator(c); }
Iterator end() { return Iterator(c+size); }
};
But I don’t understand what type should T be so that I can use the iterator object? If it is int, then what about
Iterator begin() { return Iterator(c); }
Iterator end() { return Iterator(c+size); }
Note:
FigureOfCircles (int sz) : size(sz) {
c = new T[size];
for (int i = 0; i < size; i++)
c[i].input();
for (Iterator i = begin(); i != end(); ++i) {
*i = T(i-begin());
}
}
...
int main () {
//...
FigureOfCircles f(2);
FigureOfCircles::Iterator i;
for (i = f.begin(); i != f.end(); i++) cout << *i << endl;
}
You have an array of Circles, pointed by c. An iterator should point to elements of this array. The simplest solution is to use a plain pointer. That is, T in your iterator should be just Circle.
If you want to use int (it should be std::ptrdiff_t), your iterator should also keep a pointer to the first element. In this particular example I don't see a reason to do it.
operator- should return the difference between pointers, std::ptrdiff_t, not Circle:
friend std::ptrdiff_t operator-(Iterator x, Iterator y) {
return x.t - y.t;
}
Take Iterator by value. It's just a single pointer, you don't need to take it by const-ref (effectively taking a pointer to a pointer).
Once you have iterators, you can use the standard library algorithms to make copies: instead of
for (Iterator i = begin(); i != end(); ++i) *i = f.c[i - begin()];
you can write
std::copy(f.begin(), f.end(), begin());
I suggest you use std::vector<Circle> instead of Circle*. Then you'll be able to borrow its iterators:
class FigureOfCircles {
private:
std::vector<Circle> c;
public:
std::vector<Circle>::iterator begin() {
c.begin();
}
std::vector<Circle>::iterator end() {
c.end();
}
};
This will also save you from writing a copy constructor and destructor.
While #Evg's answer is valid, it is not clear from your question why would even need to write your own iterator. If, instead of a pair of pointer+length members, you would use an std::vector or std::array - or even std::span which is oblivious to where you get your buffer from - you could use these classes' respective iterators instead of implementing your own.
It is only if you have some special behavior in your FigureOfCircles class - e.g. element skipping, non-standard iteration order and so on - that you really need a custom iterator.
PS - The naming is a bit awkward. If a Figure can only have Circles, then just call the class Figure. If there are Figures of something other than Circles, try: template <typename Element> class Figure { ... } and then you'll use Figure<Circle>.
I implemented my first custom iterator, which is supposed to return an std::pair at each iteration. The only problem, is it loops infinitely and I do not know how to provide stop condition. The code looks like so:
#include <iostream>
#include <vector>
#include <utility>
class Simple
{
private:
std::vector<std::size_t> indices;
std::vector<int> values;
public:
void insert(std::size_t index, int value)
{
indices.push_back(index);
values.push_back(value);
}
int at(std::size_t index)
{
return values[indices[index]];
}
class Iterator
{
private:
const std::vector<std::size_t>* indices;
const std::vector<int>* values;
std::size_t pos = 0;
public:
Iterator(const std::vector<std::size_t>* indices_, const std::vector<int>* values_, const std::size_t &pos_ = 0):
values(values_), indices(indices_), pos(pos_){ }
bool operator==(const Iterator& other){
return this == &other;
}
bool operator!=(const Iterator& other){
return !operator==(other);
}
Iterator operator++() {
pos++;
Iterator i = *this;
return i;
}
std::pair<std::size_t, int> operator*()
{
if (pos < (*values).size())
{
return std::make_pair((*indices)[pos], (*values)[pos]);
}
std::cout << "EMPTY PAIR" << std::endl; //loops infinitely and prints this message
return std::pair<std::size_t,int>{};
}
std::pair<std::size_t, int>* operator->()
{
if (pos < (*values).size())
{
std::pair<std::size_t,int> *p;
*p = std::make_pair((*indices)[pos], (*values)[pos]);
return p;
}
return nullptr;
}
};
Iterator begin() const
{
return Iterator(&indices, &values, 0);
}
Iterator end() const
{
return Iterator(&indices, &values, values.size());
}
};
int main() {
Simple s;
s.insert(10, 100);
std::cout << s.at(10) << std::endl;
int i = 0;
for (const std::pair<std::size_t, int> &p : s)
{
std::cout << p.first << " " << p.second << std::endl;
if (i > 3) break; // otherwise it will loop infinitely
i++;
}
return 0;
}
I would like to stress, that this example is simplified and for demonstration purposes, so you may not ask me, why I'm not using map or unorded_map (just because what I'm implementing looks like a map). The question is solely about iterator and I need understanding what may be wrong with iterator itself and how to provide stop condition.
I'm writing an implementation of Deque as a programming exercise and it's not going too well at all. I'm missing a few key function that are needed to make the test main program I was given function correctly.
Here is my code so far:
#include <vector>
#include <iostream>
#include <cassert>
using namespace std;
template <class T> class DequeIterator;
template <class T>
class Deque {
public:
typedef DequeIterator<T> iterator;
Deque(): vecOne(), vecTwo() { }
Deque(unsigned int size, T& initial): vecOne(size/2, initial), vecTwo(size-(size/2), initial) { }
Deque(Deque<T> & d): vecOne(d.vecOne), vecTwo(d.vecTwo) { }
T & operator[](unsigned int);
T & front();//
T & back();//
bool empty(){ return vecOne.empty() && vecTwo.empty(); }
iterator begin() { return iterator(this,0); }
iterator end() { return iterator(this, size ()); }
void erase(const iterator &);
void erase(const iterator &, const iterator &);
void insert(const iterator &, const T &);
int size() { return vecOne.size() + vecTwo.size(); }
void push_front(const T & value) { vecOne.push_back(value); }
void push_back(const T & value) {vecTwo.push_back(value); }
void pop_front();
void pop_back();
protected:
vector<T> vecOne;
vector<T> vecTwo;
};
template <class T>//
T & Deque<T>::front()//returns the first element in the deque
{
if (vecOne.empty())
return vecTwo.front();
else
return vecOne.back();
}
template <class T>//
T & Deque<T>::back()//returns the last element in the deque
{
if (vecOne.empty())
return vecTwo.back();
else
return vecOne.front();
}
template <class T>//
T & Deque<T>::operator[] (unsigned int index)
{
int n = vecOne.size();
if (index < n)
return vecOne [ (n-1) - index ];
else
return vecTwo [ index - n ];
}
template <class T>//
Deque<T>::iterator DequeIterator<T>::operator ++ (int)
{
Deque<T>::iterator clone(theDeque, index);
index++;
return clone;
}
template <class T>//
void Deque<T>::pop_front()
{
}
template <class T>//
void Deque<T>::pop_back()
{
}
template <class T>//
void Deque<T>::erase (const iterator & itr)
{
int index = itr.index;
int n = vecOne.size();
if (index < n)
vecOne.erase (vecOne.begin() + ((n-1) - index));
else
vecTwo.erase (vecTwo.begin() + (n - index));
}
template <class T>//
void Deque<T>::erase (const iterator &, const iterator &)
{
}
template <class T>//
void Deque<T>::insert(const iterator &, const T &)
{
}
template <class T>
class DequeIterator {
friend class Deque<T>;
typedef DequeIterator<T> iterator;
public:
DequeIterator(): theDeque(0), index(0) { }
DequeIterator(Deque<T> * d, int i): theDeque(d), index(i) { }
DequeIterator(const iterator & d): theDeque(d.theDeque), index(d.index) { }
T & operator*() { return (*theDeque)[index]; }
iterator & operator++(int) { ++index; return *this; }
iterator operator++();
iterator operator--(int) { --index; return *this; }
iterator & operator--();
bool operator==(const iterator & r) { return theDeque == r.theDeque && index == r.index; }
bool operator!=(const iterator & r) { return theDeque == r.theDeque && index != r.index; }
bool operator< (const iterator & r) { return theDeque == r.theDeque && index < r.index; }
T & operator[](unsigned int i) { return (*theDeque) [index + i]; }
iterator operator=(const iterator & r) { theDeque = r.theDeque; index = r.index; }
iterator operator+(int i) { return iterator(theDeque, index + i); }
iterator operator-(int i) { return iterator(theDeque, index - i); }
protected:
Deque<T> * theDeque;
int index;
};
main()
{
Deque<int> d;
d.push_back(10);
d.push_back(20);
assert(d.front() == 10);
assert(d.back() == 20);
d.push_front(1);
d.push_front(2);
d.push_front(3);
assert(d.front() == 3);
assert(d.back() == 20);
d.pop_back();
d.pop_back();
d.pop_back();
assert(d.front() == 3);
assert(d.back() == 2);
d.push_back(1);
d.push_back(0);
Deque<int>::iterator i;
int counter = 3;
for (i = d.begin(); i != d.end(); i++)
assert(*i == counter--);
for (counter = 0; counter < d.size(); counter++)
assert(d[counter] == d.size()-counter-1);
i = d.begin() + 3;
Deque<int>::iterator j(i), k;
k = j = i - 2;
assert(*k == 2);
for (i = d.begin(); not(i == d.end()); ++i)
cout << *i << " ";
cout << endl;
d.erase(d.begin()+3);
//d.erase(d.begin(), d.begin()+2);
assert(d.size() == 1);
assert(d[0] == 1);
Deque<int> c(d);
c.front() = 3;
assert(c.back() == 3);
c.push_front(1);
c.insert(c.begin(), 0);
c.insert(c.begin()+2, 2);
for (i = c.begin(); not(i == c.end()); ++i)
cout << *i << " ";
cout << endl;
for (counter = 0; counter < c.size(); counter++)
assert(c[counter] == counter);
cout << "SUCCESS\n";
}
I was wondering if someone could tell me my function from line 66 is returning:
expected constructor, destructor, or type conversion before 'DequeIterator'
Because I'm not sure what I'm doing wrong in it. Also, if someone would be kind enough to give me an example of the pop_front() function so that I can use it to create the pop_back() function as well, that would be great. Lastly, I have on of the erase functions completed but I am not sure how to go about creating the second one, which basically erases a value within the range of two iterators, it is referenced in line 176.
Any help would be greatly appreciated. Thank you in advance.
As for the error, you probably need a typename before Deque<T>::iterator on that line.
typename Deque<T>::iterator DequeIterator<T>::operator++(int)
I think it is a great programming exercise to implement deque. But a prerequisite is to implement vector and list. deque is one of the most complicated std::containers to implement. You should start with one of the simpler ones (vector and list).
Well, you get the error on line 65 because you return an object of a class that hasn't been defined. You only have the forward declaration (prototype) for class DequeIterator, not the implementation.
void pop_back() {
vecTwo.pop_back();
}
void pop_front() {
vecOne.pop_back();
}