I tried to implement iterators for a class of mine and surprisingly I got the following:
warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second
candidate 1: 'Iterator Iterator::operator+(const ptrdiff_t&) [with T = int; ptrdiff_t = long long int]'
candidate 2: 'operator+(int, unsigned int)'
Here's the Iterator code:
template<typename T>
class Iterator {
public:
Iterator(T *p = nullptr) { this->ptr = p; }
Iterator(const Iterator<T>& iter) = default;
Iterator<T>& operator=(const Iterator<T>& iter) = default;
Iterator<T>& operator=(T* p) { this->ptr = p; return *this; }
operator bool() const { return this->ptr ? true : false; }
bool operator==(const Iterator<T>& p) const { return this->ptr == p.getConstPtr(); }
bool operator!=(const Iterator<T>& p) const { return this->ptr != p.getConstPtr(); }
Iterator<T>& operator+=(const ptrdiff_t& v) { this->ptr += v; return *this; }
Iterator<T>& operator-=(const ptrdiff_t& v) { this->ptr -= v; return *this; }
Iterator<T>& operator++() { ++this->ptr; return *this; }
Iterator<T>& operator--() { --this->ptr; return *this; }
Iterator<T> operator++(int) { auto temp(*this); ++this->ptr; return temp; }
Iterator<T> operator--(int) { auto temp(*this); --this->ptr; return temp; }
Iterator<T> operator+(const ptrdiff_t& v) { auto oldPtr = this->ptr; this->ptr += v; auto temp(*this); this->ptr = oldPtr; return temp; }
Iterator<T> operator-(const ptrdiff_t& v) { auto oldPtr = this->ptr; this->ptr -= v; auto temp(*this); this->ptr = oldPtr; return temp; }
ptrdiff_t operator-(const Iterator<T>& p) { return std::distance(p.getPtr(), this->getPtr()); }
T& operator*() { return *(this->ptr); }
const T& operator*() const { return *(this->ptr); }
T* operator->() { return this->ptr; }
T* getPtr() const { return this->ptr; }
const T* getConstPtr() const { return this->ptr; }
private:
T *ptr;
};
And here's how I typedef it inside my class:
template<typename T>
class ExampleClass {
public:
// ...
typedef Iterator<T> iterator;
typedef Iterator<const T> const_iterator;
// ...
iterator begin() { return iterator(&this->ptr()[0]); }
iterator end() { return iterator(&this->ptr()[this->size()]); }
const_iterator cbegin() { return const_iterator(&this->ptr()[0]); }
const_iterator cend() { return const_iterator(&this->ptr()[this->size()]); }
// ...
// A function where I use the operator+
void slice(unsigned int first, unsigned int last) {
// ...
auto it = this->begin() + first; // <--------
// ...
}
};
Maybe I am missing something but how (Iterator, ptrdiff_t) and (int, unsigned int) are ambiguous?
I haven't compiled this, but the problem appears to be that operator bool(); it provides an implicit conversion to bool, which is, in turn, convertible to int. Iterators in general don't provide their own validation, so this is unusual. If you need it, mark it explicit. That will prevent the implicit conversion.
Related
Let's suppose I have two classes, the first:
class IntMatrix::iterator {
private:
const IntMatrix *int_matrix;
int index;
iterator(const IntMatrix *int_matrix, int index);
friend class IntMatrix;
public:
int &operator*() const;
iterator &operator++();
iterator operator++(int);
bool operator==(const iterator &it) const;
bool operator!=(const iterator &it) const;
iterator(const iterator &) = default;
iterator &operator=(const iterator &) = default;
~iterator() = default;
};
and the second is:
class IntMatrix::const_iterator {
private:
const IntMatrix *int_matrix;
int index;
const_iterator(const IntMatrix *int_matrix, int index);
friend class IntMatrix;
public:
const int &operator*() const;
const_iterator &operator++();
const_iterator operator++(int);
bool operator==(const const_iterator &it) const;
bool operator!=(const const_iterator &it) const;
const_iterator(const const_iterator &) = default;
const_iterator &operator=(const const_iterator &) = default;
~const_iterator() = default;
};
How may I prevent code duplication here, since the implementation is 99% the same?
How about generics may it help here or inheritance?
An example of how they are implemented:
int &IntMatrix::iterator::operator*() const {
return int_matrix->data[index];
}
const int &IntMatrix::const_iterator::operator*() const {
return int_matrix->data[index];
}
Plus, I want In main to allow something like:
IntMatrix::iterator it;
Update:
I'm trying to implement the given solution on a Generic class called Matrix in the following way: (Note the code shown is all written as public in my class)
template<typename T>
class iterator_impl;
template<typename T>
iterator_impl<T> begin(){
return iterator(this, 0);
}
template<typename T>
iterator_impl<T> end(){
return iterator(this, size());
}
template<typename T>
iterator_impl<const T> begin() const
{
return const_iterator(this, 0);
}
template<typename T>
iterator_impl<const T> end() const
{
return const_iterator(this, size());
}
template<typename T>
class iterator_impl{
private:
const Matrix<T> *matrix;
int index;
friend class Matrix<T>;
public:
iterator_impl(const iterator_impl &) = default;
iterator_impl &operator=(const iterator_impl &) = default;
~iterator_impl() = default;
iterator_impl(const Matrix<T> *int_matrix, int index)
: matrix(int_matrix), index(index) {}
iterator_impl &operator++()
{
++index;
return *this;
}
iterator_impl operator++(int)
{
iterator_impl result = *this;
++*this;
return result;
}
bool operator==(const iterator_impl &it) const
{
return index == it.index;
}
bool operator!=(const iterator_impl &it) const
{
return !(*this == it);
}
T &operator*() const {
if (index < 0 || index > matrix->size() - 1) {
throw Matrix<T>::AccessIllegalElement();
}
return matrix->data[index];
}
};
template<typename T>
using iterator = iterator_impl<T>;
template<typename T>
using const_iterator = iterator_impl<const T>;
and I'm getting some errors like:
invalid use of 'this' outside of a non-static member function
return iterator(this, 0);
One way is to make the implementation into a class template and then to make aliases for the const and non-const instantiations.
Plus, I want In main to allow something like:
IntMatrix::iterator it;
You then need to add a default constructor.
Example:
#include <cstddef>
#include <type_traits>
// in the .hpp file:
class IntMatrix {
private:
int data[10]; // just an example
size_t size = 10; // just an example
template<typename T>
class iterator_impl;
public:
// two typedefs using the template:
using iterator = iterator_impl<int>;
using const_iterator = iterator_impl<const int>;
const_iterator cbegin() const;
const_iterator cend() const;
const_iterator begin() const;
const_iterator end() const;
iterator begin();
iterator end();
};
// still in the .hpp file:
template<typename T>
class IntMatrix::iterator_impl {
public:
using matrix_type =
std::conditional_t<
std::is_const_v<T>,
const IntMatrix,
IntMatrix
>;
private:
matrix_type* int_matrix;
size_t index;
friend IntMatrix;
iterator_impl(matrix_type* im, size_t idx) :
int_matrix(im), index(idx)
{}
public:
iterator_impl() = default; // default constructor
//iterator_impl(const iterator_impl&) = default; // not needed
//iterator_impl &operator=(const iterator_impl &) = default; // not needed
//~iterator_impl() = default; // not needed
iterator_impl &operator++() {
++index;
return *this;
}
iterator_impl operator++(int) {
iterator_impl old(*this);
++index;
return old;
}
bool operator!=(const iterator_impl &it) const {
return index != it.index || int_matrix != it.int_matrix;
}
bool operator==(const iterator_impl &it) const {
return !(*this != it);
}
T& operator*() const {
return int_matrix->data[index];
}
};
// in the .cpp file:
IntMatrix::const_iterator IntMatrix::cbegin() const { return {this, 0}; }
IntMatrix::const_iterator IntMatrix::cend() const { return {this, size}; }
IntMatrix::const_iterator IntMatrix::begin() const { return cbegin(); }
IntMatrix::const_iterator IntMatrix::end() const { return cend(); }
IntMatrix::iterator IntMatrix::begin() { return {this, 0}; }
IntMatrix::iterator IntMatrix::end() { return {this, size}; }
Demo
Edit: If Matrix is a class template itself, you need to change the iterator slightly.
#include <cstddef>
#include <type_traits>
// in the .hpp file:
template<typename T>
class Matrix {
private:
T data[10]; // just an example
size_t size = 10; // just an example
template<typename I>
class iterator_impl;
public:
// two typedefs using the template:
using iterator = iterator_impl<T>;
using const_iterator = iterator_impl<const T>;
auto cbegin() const;
auto cend() const;
auto begin() const;
auto end() const;
auto begin();
auto end();
};
// still in the .hpp file:
template<typename T>
template<typename I>
class Matrix<T>::iterator_impl {
public:
using value_type = std::remove_const_t<I>;
using matrix_type =
std::conditional_t<
std::is_const_v<I>,
const Matrix<value_type>,
Matrix<value_type>
>;
private:
matrix_type* matrix;
size_t index;
friend Matrix;
iterator_impl(matrix_type* im, size_t idx) :
matrix(im), index(idx)
{}
public:
iterator_impl() = default; // default constructor
iterator_impl& operator++() {
++index;
return *this;
}
iterator_impl operator++(int) {
iterator_impl old(*this);
++index;
return old;
}
bool operator!=(const iterator_impl &it) const {
return index != it.index || matrix != it.matrix;
}
bool operator==(const iterator_impl &it) const {
return !(*this != it);
}
I& operator*() const {
return matrix->data[index];
}
};
// still in the .hpp file
template<typename T> auto Matrix<T>::cbegin() const { return const_iterator{this, 0}; }
template<typename T> auto Matrix<T>::cend() const { return const_iterator{this, size}; }
template<typename T> auto Matrix<T>::begin() const { return cbegin(); }
template<typename T> auto Matrix<T>::end() const { return cend(); }
template<typename T> auto Matrix<T>::begin() { return iterator{this, 0}; }
template<typename T> auto Matrix<T>::end() { return iterator{this, size}; }
Demo
I'm writting a STL like vector and an iterator class for it. And today while writting erase func which takes const_iterator, it turned out that there is not the conversation from iterator to const_iterator.I tried to find some information, but I still don't know how to make it. But STL vector makes it somehow.
My Iterator class:
template<typename VectorDataType>
class Iterator{
public:
using value_type = VectorDataType;
using difference_type = int;
using pointer = VectorDataType*;
using reference = VectorDataType&;
using iterator_category = std::random_access_iterator_tag;
public:
explicit Iterator(VectorDataType* ptr = nullptr)
: ptr(ptr){}
Iterator(const Iterator<VectorDataType>& iter)
: ptr(iter.ptr){}
~Iterator() {ptr = nullptr;}
template<template<typename Y> class Alloc>
operator typename Vector<VectorDataType, Alloc>::const_iterator (){
typename Vector<VectorDataType, Alloc>::const_iterator citer(*this);
return citer;
}
Iterator& operator=(VectorDataType* rhs) {this->ptr = rhs; return *this;}
Iterator& operator=(const Iterator& rhs) {this->ptr = rhs.ptr; return *this;}
operator bool() const{
bool result = (this->ptr) ? true : false;
return result;
}
bool operator==(const Iterator<VectorDataType>& iter) const{
return this->ptr == iter.ptr;
}
bool operator!=(const Iterator<VectorDataType>&iter) const{
return this->ptr != iter.ptr;
}
bool operator<(const Iterator<VectorDataType>& iter)const {
return this->ptr < iter.ptr;
}
bool operator>(const Iterator<VectorDataType>& iter)const {
return this->ptr > iter.ptr;
}
bool operator<=(const Iterator<VectorDataType>& iter)const {
return this->ptr <= iter.ptr;
}
bool operator>=(const Iterator<VectorDataType>& iter)const {
return this->ptr >= iter.ptr;
}
Iterator<VectorDataType>& operator+=(const difference_type& offset){
this->ptr += offset;
return *this;
}
Iterator<VectorDataType>& operator-=(const difference_type& offset){
this->ptr -= offset;
return *this;
}
Iterator<VectorDataType>& operator++(){
this->ptr++;
return *this;
}
Iterator<VectorDataType>& operator--(){
this->ptr--;
return *this;
}
Iterator<VectorDataType> operator++(int){
Iterator<VectorDataType> temp(*this);
this->ptr++;
return temp;
}
Iterator<VectorDataType> operator--(int){
Iterator<VectorDataType> temp(*this);
this->ptr--;
return temp;
}
Iterator<VectorDataType> operator+(const difference_type&offset) const{
VectorDataType* newPtr = ptr;
newPtr += offset;
return Iterator{newPtr};
}
Iterator<VectorDataType> operator-(const difference_type&offset) const{
VectorDataType* newPtr = ptr;
newPtr -= offset;
return Iterator{newPtr};
}
difference_type operator-(const Iterator<VectorDataType>& iter)const{
return std::distance(iter.ptr, this->ptr);
}
VectorDataType& operator*(){return *ptr;}
const VectorDataType& operator*()const{return *ptr;}
VectorDataType* operator->(){return ptr;}
VectorDataType& operator[](int offset){
return ptr[offset];
}
private:
VectorDataType* ptr;
};
Main's code:
auto list = {1, 2, 3, 4, 5, 6, 7, 8, 9};
Vector<int> vec(list);
for(auto&i: vec)
std::cout << i << "\t";
auto iter = vec.begin();
iter++;
iter++;
iter++;
auto pos = vec.erase(iter);
for(auto&i: vec)
std::cout << i << "\t";
erase definition:
iterator erase(const_iterator pos);
Console log:
g++ -c -pipe -g -std=gnu++1z -Wall -Wextra -fPIC -I../MyVector -I. -I../../Qt/5.14.1/gcc_64/mkspecs/linux-g++ -o main.o ../MyVector/main.cpp
../MyVector/main.cpp: In function ‘int main()’:
../MyVector/main.cpp:49:30: error: no matching function for call to ‘Vector<int>::erase(Iterator<int>&)’
auto pos = vec.erase(iter);
^
In file included from ../MyVector/main.cpp:2:0:
../MyVector/MyVector.h:601:21: note: candidate: Vector<T, Allocator>::iterator Vector<T, Allocator>::erase(Vector<T, Allocator>::const_iterator) [with T = int; Allocator = std::allocator; Vector<T, Allocator>::iterator = Iterator<int>; Vector<T, Allocator>::const_iterator = Iterator<const int>]
iterator erase(const_iterator pos){
^~~~~
../MyVector/MyVector.h:601:21: note: no known conversion for argument 1 from ‘Iterator<int>’ to ‘Vector<int>::const_iterator {aka Iterator<const int>}’
../MyVector/MyVector.h:618:21: note: candidate: Vector<T, Allocator>::iterator Vector<T, Allocator>::erase(Vector<T, Allocator>::const_iterator, Vector<T, Allocator>::const_iterator) [with T = int; Allocator = std::allocator; Vector<T, Allocator>::iterator = Iterator<int>; Vector<T, Allocator>::const_iterator = Iterator<const int>]
If you want to see all code, here is a github link: https://github.com/RRRadicalEdward/Vector/blob/master/MyVector.h
The problem with your implicit conversion operator is that it puts the template-template parameter Alloc in a non-deduced context, that is, left to the scope operator:
template <template <typename Y> class Alloc>
operator typename Vector<VectorDataType, Alloc>::const_iterator() {
// non-deduced ~~~~^
typename Vector<VectorDataType, Alloc>::const_iterator citer(*this);
return citer;
}
Thus the compiler cannot apply this conversion. Try changing it to:
operator Iterator<const VectorDataType>() const {
Iterator<const VectorDataType> citer(ptr);
return citer;
}
Note also that the constructor call argument is a pointer, not the iterator (*this) itself.
The same way as all user defined conversions:
Either
implicit converting constructor in the target type or
implicit conversion operator in the source type
I am stuck trying to understand where this error comes from:
error: ‘value_type’ in ‘struct std::iterator_traits<sha::Vector<int>::h_iterator>’ does not name a type
I am trying to create a std::vector wrapper and inherit iterator as well.
I don't get why the compilator cannot infer the 'value_type' or 'difference_type'.
Here is my class definition:
template <typename T>
class Vector
{
public:
explicit Vector(std::initializer_list<T> init) : data(init) {}
~Vector() {}
class h_iterator : std::iterator<std::random_access_iterator_tag, T>
{
public:
h_iterator(typename std::vector<T>::iterator it,
Vector<T>* owner) :
it(it), owner(owner) {}
T operator *() const { return *it; }
const h_iterator &operator ++() { ++it; return *this; }
h_iterator operator ++(int) { h_iterator copy(*this); ++it; return copy; }
const h_iterator &operator --() { --it; return *this; }
h_iterator operator --(int) { h_iterator copy(*this); --it; return copy; }
h_iterator& operator =(const h_iterator& other){ this->it =other.it; return *this;}
bool operator ==(const h_iterator &other) const { return it == other.it; }
bool operator !=(const h_iterator &other) const { return it != other.it; }
bool operator <(const h_iterator &other) const { return it < other.it; }
bool operator >(const h_iterator &other) const { return it > other.it; }
bool operator <=(const h_iterator &other) const { return it <= other.it; }
bool operator >=(const h_iterator &other) const { return it >= other.it; }
h_iterator operator +(const long int &delta) const
{
h_iterator copy(*this);
it += delta;
return copy;
}
h_iterator& operator +=(const long int& delta)
{
it = it + delta;
return *this;
}
h_iterator operator -(const long int &delta) const
{
h_iterator copy(*this);
it -= delta;
return copy;
}
h_iterator& operator -=(const long int& delta)
{
it = it - delta;
return *this;
}
T operator [](const long int &delta) const { return *(it + delta); }
private:
typename std::vector<T>::iterator it; // Iterator
Vector<T>* owner; // Cannot be null as long as the iterator is valid
};
// Preserve normal iterator accesses
typename std::vector<T>::iterator begin() { return data.begin(); }
typename std::vector<T>::iterator end() { return data.end(); }
const typename std::vector<T>::iterator cbegin() const { return data.cbegin(); }
const typename std::vector<T>::iterator cend() const { return data.cend(); }
// Observale iterator
h_iterator h_begin() { return h_iterator(data.begin(), this); }
h_iterator h_end() { return h_iterator(data.end(), this); }
// Implement Meta-Language functions
//...
private:
Vector() {}
Vector operator=(Vector&) {} // Not Implemented
std::vector<T> data; // Vector wrapper
};
Here is the code that makes the compilation failed:
typedef Vector<int> Container;
typedef Container::h_iterator IT;
typedef std::less<typename
std::iterator_traits<Vector<int>::h_iterator>::value_type> Compare;
Why does this compile error happen?
When you use:
class h_iterator : std::iterator<std::random_access_iterator_tag, T>
the base class is a private base class. The details of the base class are not accessible to clients of h_iterator. Make the derivation public.
class h_iterator : public std::iterator<std::random_access_iterator_tag, T>
I've implemented a random_access_iterator for a custom library (which is templated to be reused both as const iterator and non-const iterator), but it's causing memory leaks while doing something like std::sort(container.begin(), container.end() (container.begin()/end() return iterator instance.
What's wrong with my implementation?
template <bool is_const_iterator = false>
class meta_iterator : public std::iterator<std::random_access_iterator_tag, T> {
public:
typedef T value_type;
typedef std::ptrdiff_t difference_type;
typedef typename std::conditional<is_const_iterator, const value_type &,
value_type &> reference;
typedef std::random_access_iterator_tag iterator_category;
typedef typename std::conditional<is_const_iterator, value_type const *,
value_type *>::type pointer;
typedef meta_iterator self_type;
meta_iterator(T *ptr) : ptr_(ptr) {}
meta_iterator(const meta_iterator<true> &other) : ptr_(other.ptr_) {}
self_type operator+(difference_type value) {
ptr_ += value;
return *(this);
};
self_type operator-(difference_type value) {
ptr_ -= value;
return *(this);
};
difference_type operator-(const self_type &other) {
return ptr_ - other.ptr_;
}
T &operator[](difference_type value) const { return *ptr_[value]; }
bool operator==(const self_type &other) const { return ptr_ == other.ptr_; }
bool operator!=(const self_type &other) const { return !(*this == other); }
bool operator>=(const self_type &other) const { return !((*this) < other); }
bool operator<=(const self_type &other) const { return !((*this) > other); }
bool operator<(const self_type &other) const { return ptr_ < other.ptr_; }
bool operator>(const self_type &other) const { return ptr_ < other.ptr_; }
self_type &operator=(const self_type &other) {
ptr_ = other.ptr_;
return *(this);
}
T *operator->() const { return ptr_; }
T &operator*() const { return *ptr_; }
self_type &operator--() {
ptr_--;
return *this;
}
self_type operator--(int) {
self_type temp(*this);
--(*this);
return (temp);
}
self_type &operator++() {
ptr_++;
return *this;
}
self_type operator++(int) {
self_type temp(*this);
--(*this);
return (temp);
}
self_type &operator+=(difference_type value) {
ptr_ += value;
return *(this);
}
self_type &operator-=(difference_type value) {
ptr_ -= value;
return *(this);
}
friend class meta_iterator<true>;
friend class meta_iterator<false>;
private:
T *ptr_;
};
Don't know if it causes a memory leak, but these two operators
self_type operator+(difference_type value) {
ptr_ += value;
return *(this);
};
self_type operator-(difference_type value) {
ptr_ -= value;
return *(this);
};
should just return a new iterator, and not update the stored ptr_.
Also, there is a typo in
self_type operator++(int) {
self_type temp(*this);
--(*this);
return (temp);
}
making it go in the wrong direction. That will probably confuse some loops.
Following on from this question: std::list implementation & pointer arithemetic.
I want to implement a list iterator that is interchangeable with other common containers types and their respective iterators, so I want to use operators such as: --, ++, * and be able to declare iterators as normal, so: list::iterator iter = list.begin();
The --, ++ operators now work as they should, but I ran up against the problem of de-referencing the iterator, as structs can't return a value: T iterator::operator*()
template <class T>
struct element {
element<T> *prev = NULL;
element<T> *next = NULL;
T data;
};
template <typename T>
class list {
public:
list::list();
element<T>* current;
struct iterator{
element<T>* iterator::operator++(){
this = *this->next; ..whatever it works
}
element<T>* iterator::operator--()
T iterator::operator*()
}
};
the iterators could look something like this:
(declared inside the list template)
struct iterator;
struct const_iterator : public std::iterator<std::bidirectional_iterator_tag, const T>
{
const_iterator() = default;
T operator*() { return itm->data; }
const T* operator->() { return &(itm->data); }
const_iterator operator++() { itm = itm->next; return *this; }
const_iterator operator--() { itm = itm->prev; return *this; }
const_iterator operator++(int) { const_iterator ret=*this; itm = itm->next; return ret; }
const_iterator operator--(int) { const_iterator ret=*this; itm = itm->prev; return ret; }
bool operator==(const_iterator oth) const { return itm==oth.itm; }
bool operator!=(const_iterator oth) const { return itm!=oth.itm; }
private:
element<T>* itm = nullptr;
const_iterator(element<T>* i) : itm(i) {}
friend
class list;
friend
struct iterator;
};
struct iterator : public std::iterator<std::bidirectional_iterator_tag, T>
{
iterator() = default;
T& operator*() { return itm->data; }
T* operator->() { return &(itm->data); }
iterator operator++() { itm = itm->next; return *this; }
iterator operator--() { itm = itm->prev; return *this; }
iterator operator++(int) { iterator ret=*this; itm = itm->next; return ret; }
iterator operator--(int) { iterator ret=*this; itm = itm->prev; return ret; }
bool operator==(iterator oth) const { return itm==oth.itm; }
bool operator!=(iterator oth) const { return itm!=oth.itm; }
operator const_iterator() { return {itm}; }
private:
element<T>* itm = nullptr;
iterator(element<T>* i) : itm(i) {}
friend
class list;
};
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
this needs
#include <iterator>
to compile