Accessing an outer public member from an inner class - c++

I have the following classes and I am trying to overload the operator* from the inner class iterator
#ifndef __LISTMAP_H__
#define __LISTMAP_H__
#include "xless.h"
#include "xpair.h"
template <typename Key, typename Value, class Less=xless<Key>>
class listmap {
public:
using key_type = Key;
using mapped_type = Value;
using value_type = xpair<const key_type, mapped_type>;
private:
Less less;
struct node;
struct link {
node* next{};
node* prev{};
link (node* next, node* prev): next(next), prev(prev){}
};
struct node: link {
value_type value{};
node (node* next, node* prev, const value_type&);
};
node* anchor() { return static_cast<node*> (&anchor_); }
link anchor_ {anchor(), anchor()};
public:
class iterator;
listmap(){};
listmap (const listmap&) = default;
listmap& operator= (const listmap&) = default;
~listmap();
iterator insert (const value_type&);
iterator find (const key_type&);
iterator erase (iterator position);
iterator begin() { return anchor()->next; }
iterator end() { return anchor(); }
bool empty() const { return begin() == end(); }
};
template <typename Key, typename Value, class Less>
class listmap<Key,Value,Less>::iterator {
private:
friend class listmap<Key,Value>;
listmap<Key,Value,Less>::node* where {nullptr};
iterator (node* where): where(where){};
public:
iterator(){}
value_type& operator*();
value_type* operator->();
iterator& operator++(); //++itor
iterator& operator--(); //--itor
void erase();
bool operator== (const iterator&) const;
bool operator!= (const iterator&) const;
};
template <typename Key, typename Value, class Less>
value_type& listmap<Key,Value,Less>::iterator<Key,Value,Less>::operator*()
{
return where->value;
}
#include "listmap.tcc"
#endif
The problem is that value_type is a public member from the class listmap and it's not static, so I don't know how to complete the declaration of operator*(). I wouldn't like to fix the bug by changing the structure of the code. Ex: making
using value_type = xpair<const key_type, mapped_type>;
Global. I am just wondering if there is some other trick I can use to access value_type.
....edit: I have no idea how the inner class recognizes value_type

It's barely the same as for iterator, you just have to add typename keyword
typename listmap<Key,Value,Less>::value_type
staticness doesn't matter for a type.
The alias1 inside iterator
template <typename Key, typename Value, class Less>
class listmap<Key,Value,Less>::iterator {
...
using value_type = typename listmap<Key,Value,Less>::value_type;
};
allows you to write the definition more succinctly using auto suffix type:
template <typename Key, typename Value, class Less>
auto listmap<Key,Value,Less>::iterator::operator*() -> value_type&
{
return where->value;
}
Careful: inner iterator class is not template, only listmap is:
listmap<Key,Value,Less>::iterator<Key,Value,Less>::operator
// ~~~~~~~~~~~~~~~~ remove this
1 Btw don't forget the others.

Related

Custom container list: problem with compiling from iterator to const_iterator

I am trying to recreate some of the C++ containers for a school project and for that I had to also implement iterators. I am currently working on the List container and I am facing a conversion problem.
Here are the parts of the code that are involved:
I have an Elem structure (corresponding to 1 element of a doubly linked list that I use for my List container)
template <class T>
struct Elem
{
Elem *prev;
T data;
Elem *next;
};
a BidirectionalIterator class (used for the list iterators). Here are the constructors:
template <class T>
class BidirectionalIterator
{
public:
typedef BidirectionalIterator iterator;
typedef T value_type;
typedef size_t size_type;
BidirectionalIterator() { _ptr = nullptr; };
BidirectionalIterator(Elem<value_type> *ptr) {
*this->_ptr = ptr;
};
BidirectionalIterator(const iterator &x) {
*this->_ptr = x._ptr;
};
~BidirectionalIterator() {};
iterator &operator=(const iterator &x) {
*this->_ptr = x._ptr;
return (*this);
};
[...]
};
and my list class:
template <class T, class Alloc = std::allocator<T>>
class list
{
public:
typedef T value_type;
typedef BidirectionalIterator<T> iterator;
typedef BidirectionalIterator<const T> const_iterator;
typedef size_t size_type;
/* CONSTRUCTORS */
[...]
list(const list &x) {
_init_list();
assign(x.begin(), x.end());
};
/* ITERATORS */
iterator begin() {
return (iterator(_start));
};
const_iterator begin() const {
return (const_iterator(_start));
};
iterator end() {
return (iterator(_tail));
};
const_iterator end() const {
return (const_iterator(_tail));
};
/* ASSIGN */
void assign(iterator first, iterator last);
void assign(const_iterator first, const_iterator last);
[...]
private:
Elem<value_type> *_head;
Elem<value_type> *_start;
Elem<value_type> *_end;
Elem<value_type> *_tail;
[...]
};
In my main program I' m just calling a function (T being an int) that implicitely calls the copy constructor:
void print_content(ft::list<T> lst);
But when I compile i get this:
./List.hpp:71:12: error: no matching conversion for functional-style cast from 'Elem<ft::list<int, std::allocator<int>
>::value_type> *const' (aka 'Elem<int> *const') to 'ft::list<int, std::allocator<int> >::const_iterator' (aka
'BidirectionalIterator<const int>')
return (const_iterator(_start));
^~~~~~~~~~~~~~~~~~~~~
./List.hpp:53:13: note: in instantiation of member function 'ft::list<int, std::allocator<int> >::begin' requested
here
assign(x.begin(), x.end());
./../Iterator/BidirectionalIterator.hpp:45:3: note: candidate constructor not viable: no known conversion from
'Elem<ft::list<int, std::allocator<int> >::value_type> *const' (aka 'Elem<int> *const') to
'Elem<ft::BidirectionalIterator<const int>::value_type> *' (aka 'Elem<const int> *') for 1st argument
BidirectionalIterator(Elem<value_type> *ptr) {
I don't know how to fix that problem. I already tried to delete the const attribute from my copy constructor and it works, but it needs to be const (for the rest of my project cause I'm implementing the relational operators that call a const list, and also to respect the original container constructor).
Does anyone have an idea?
You try to create an Elem<const int>* from an Elem<int> *const.
I suggest making the iterator's pointer Elem<std::remove_const_t<T>>* (even for a const_iterator) but let dereferencing a const_iterator return a T const& or T const *.
Example:
template <class T>
class BidirectionalIterator {
public:
using value_type = T;
using reference = value_type&;
using pointer = value_type*;
using size_type = std::size_t;
BidirectionalIterator() : _ptr(nullptr) {};
BidirectionalIterator(Elem<std::remove_const_t<value_type>>* ptr) : _ptr(ptr) {};
BidirectionalIterator(const BidirectionalIterator& x) {
_ptr = x._ptr;
};
BidirectionalIterator& operator=(const BidirectionalIterator& x) {
_ptr = x._ptr;
return *this;
};
reference operator*() const { return _ptr->data; }
pointer operator->() const { return &_ptr->data; }
Elem<std::remove_const_t<value_type>>* _ptr;
};
A slightly better version to let you create lists of const Ts and to also let you convert iterators to const_iterators (but not the other way around) to be able to compare iterators could look like this:
#include <memory>
#include <type_traits>
template <class T, class ElemType> // const or non-const T and the type used in Elem
class BidirectionalIterator {
public:
using value_type = T;
using reference = value_type&;
using pointer = value_type*;
using size_type = std::size_t;
BidirectionalIterator() : _ptr(nullptr) {};
BidirectionalIterator(Elem<ElemType>* ptr) : _ptr(ptr) {};
// let a conversion constructor of the const_iterator read _ptr
friend class BidirectionalIterator<const ElemType, ElemType>;
// enable a const_iterator to be created from a non-const iterator via
// a conversion constructor
template<typename U = T, typename V = ElemType,
std::enable_if_t<std::is_const_v<U>&&!std::is_const_v<V>, int> = 0
>
BidirectionalIterator(const BidirectionalIterator<ElemType, ElemType>& x) :
_ptr(x._ptr) {}
// normal copy ctor
BidirectionalIterator(const BidirectionalIterator& x) : _ptr(x._ptr) {}
BidirectionalIterator& operator=(const BidirectionalIterator& x) {
_ptr = x._ptr;
return *this;
};
// the conversion constructor lets you compare a const_iterator and an iterator
bool operator==(const BidirectionalIterator& rhs) const {
return _ptr == rhs._ptr;
}
bool operator!=(const BidirectionalIterator& rhs) const {
return !(_ptr == rhs._ptr);
}
reference operator*() const { return _ptr->data; }
pointer operator->() const { return &_ptr->data; }
private:
Elem<ElemType>* _ptr;
};
// iterator == const_iterator, swap order to use member operator==
template<typename T>
bool operator==(const BidirectionalIterator<T, T>& a,
const BidirectionalIterator<const T, T>& b) {
return b == a;
}
// iterator != const_iterator, swap order to use member operator!=
template<typename T>
bool operator!=(const BidirectionalIterator<T, T>& a,
const BidirectionalIterator<const T, T>& b) {
return b != a;
}
With this iterator definition, you'd need to define your iterator and const_iterator slightly different.
template <class T, class Alloc = std::allocator<T>>
class list {
public:
using value_type = T;
using iterator = BidirectionalIterator<T, T>;
using const_iterator = BidirectionalIterator<const T, T>;
//...

How const_iterators are implemented?

#include <iostream>
template <typename T>
struct Node
{
T value;
Node<T>* next;
};
template <typename T>
struct LinkedList
{
// head, tail....
// some implementation...
};
template<
template<typename> typename node,
typename T,
template<typename> typename iterator,
template<typename> typename const_iterator
>
struct SomeComonFunctionsBetweenIterators
{
node<T>* ptr;
// some implementation...
SomeComonFunctionsBetweenIterators(node<T>* ptr) : ptr(ptr) {}
T& operator*() { return ptr->value; }
iterator<T> GetIterator() { return iterator<T>(ptr); }
// doesn't work. want some way like this instead of passing the
// const iterator as a template argument.
//operator const_iterator<T>() { return iterator<const T>(ptr) ; }
operator const_iterator<T>() { return const_iterator<T>(ptr); }
};
template <typename T>
struct LinkedListConstIterator;
template <typename T>
struct LinkedListIterator
: public SomeComonFunctionsBetweenIterators<Node, T, LinkedListIterator, LinkedListConstIterator>
{
LinkedListIterator(Node<T>* ptr)
: SomeComonFunctionsBetweenIterators<Node, T, LinkedListIterator, LinkedListConstIterator>(ptr) {}
// some implementation...
};
template <typename T>
struct LinkedListConstIterator : public LinkedListIterator<T>
{
LinkedListConstIterator(Node<T>* ptr) : LinkedListIterator<T>(ptr) {}
const T& operator*() { return static_cast<const T&>(this->ptr->value); }
};
int main()
{
Node<int> node{ 5, nullptr };
LinkedListIterator<int> it(&node);
std::cout << *it << '\n';
LinkedListConstIterator<int> cit = it;
std::cout << *cit << '\n';
}
In this code I have a linked list and an iterator to it. Also I have a const iterator which inherits from the normal iterator and when dereferenced, returns a const T. The iterator can be for a singly linked list or a doubly linked list and most of the functions in both of them are the same (dereferencing or comparing for example). So I extracted the common functions and put it in a common struct. I want to be able to asign normal iterators to const iterators. So I pass the const iterator to the normal iterator as a template argument and define a conversion operator from the normal iterator to const iterator. This way works but it requires me to always pass the const iterator alongside the normal iterator as a template argument.
Is there any better way to implement const_iterators? instead of passing the const iterator everywhere. How the const_iterators are implemented for example in the STL containers?
How the const_iterators are implemented for example in the STL containers?
You can probably look in your implementation's header files to see how they chose to do it. It will depend on the container type and its internal data structure. But the common pattern I've seen is that there's some private template that can take either non-const T or const T, and that will be used as a base or member of the actual distinct iterator types. One catch is that a specific type from the data structure needs to be used, independently of the type the iterator classes expose. In your example, Node<T> and Node<const T> are not interoperable, so SomeComonFunctionsBetweenIterators could work, but should probably have the node type as a template argument independent of the value type T.
But for an easy way to define iterator types, I always turn to Boost.Iterator's iterator_facade or iterator_adaptor. They take care of a lot of the technical requirements about iterators, letting the author just fill in the behavioral bits. iterator_facade is for implementing something "from scratch", and iterator_adaptor is for the common case of an iterator that contains and wraps another iterator.
The Boost documentation for iterator_facade discusses a way to define related iterator and const_iterator types. (Though their decision to make the iterators interoperable as long as the pointers can convert probably wouldn't be appropriate for iterators from containers.)
Using iterator_facade will also give a bunch of things algorithms may expect of iterators but missing from your code shown, like making std::iterator_traits work, equality and inequality, and other fiddly details.
#include <boost/iterator/iterator_facade.hpp>
#include <type_traits>
template <typename T>
struct Node
{
T value;
Node* next;
};
template <typename NodeType, typename ValueType, typename ContainerType>
class TLinkedListIterator :
public boost::iterator_facade<
TLinkedListIterator<NodeType, ValueType, ContainerType>, // CRTP Derived type
ValueType, // Iterator's value_type
std::forward_iterator_tag // Category
>
{
public:
TLinkedListIterator() : m_node(nullptr) {}
protected:
explicit TLinkedListIterator(NodeType* node) : m_node(node) {}
private:
friend boost::iterator_core_access;
friend ContainerType;
template <typename N, typename V, typename C> friend class TLinkedListIterator;
ValueType& dereference() const { return m_node->value; }
void increment() { m_node = m_node->next; }
// Templating allows comparison between iterator and const_iterator
// in any combination.
template <typename OtherValueType>
bool equal(const TLinkedListIterator<NodeType, OtherValueType, ContainerType>& iter)
{ return m_node == iter.m_node; }
NodeType m_node;
};
template <typename T>
class LinkedList
{
public:
using iterator = TLinkedListIterator<Node<T>, T, LinkedList>;
class const_iterator
: public TLinkedListIterator<Node<T>, const T, LinkedList>
{
private:
using BaseType = TLinkedListIterator<Node<T>, const T, LinkedList>;
public:
const_iterator() = default;
// Converting constructor for implicit conversion from iterator
// to const_iterator:
const_iterator(const iterator& iter)
: BaseType(iter.m_node) {}
protected:
explicit const_iterator(Node<T>* node)
: BaseType(node) {}
friend LinkedList<T>;
};
iterator begin() { return iterator(get_head()); }
iterator end() { return iterator(); }
const_iterator begin() const { return const_iterator(get_head()); }
const_iterator end() const { return const_iterator(); }
const_iterator cbegin() const { return begin(); }
const_iterator cend() const { return end(); }
// ...
};

Using iterators templates to copy generic datas

I'm trying to implement a template class which is almost the same as the STL implementation of list.
Now i'm working on the range overload of the std::insert() function. The prototype is :
template <class InputIterator> iterator insert (const_iterator position, InputIterator first, InputIterator last);
The problem is : i can't get the first and last iterators to do anything. Whenever i'm trying to dereference them (*first), i'm getting an "illegal indirection" error at compilation. The only operation i can perform is first++, and when i'm trying it with a std::vector<int>::iterator, first is obviously returning the next element.
Here is the most important part of my class :
template <class T>
class List {
public:
typedef T value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef std::size_t size_type;
/* Structures / Classes */
struct Node {
Node* previous;
Node* next;
Node() : previous(this), next(this) {};
Node(Node* previous) : previous(previous), next(this) {};
};
struct DataNode : public Node {
value_type data;
DataNode(const_reference data) : Node(), data(data) {};
virtual ~DataNode() {};
};
class ListIterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
{
friend class List;
private:
Node* node;
public:
ListIterator() : node(0) {};
ListIterator(Node* ptr) : node(ptr) {};
ListIterator(const ListIterator& other) : node(other.node) {};
virtual ~ListIterator() {};
ListIterator& operator++() { node = node->next; return *this; };
ListIterator operator++(int) {
ListIterator tmp(*this);
operator++();
return tmp;
};
ListIterator& operator--() { node = node->previous; return *this; };
ListIterator operator--(int) {
ListIterator tmp(*this);
operator--();
return tmp;
};
bool operator==(const ListIterator& other) { return node == other.node; };
bool operator!=(const ListIterator& other) { return node != other.node; };
ListIterator& operator=(const ListIterator& other) {
if (this != &other) this->node = other.node;
return *this;
}
value_type& operator*() { return reinterpret_cast<DataNode*>(node)->data; }
};
class ConstListIterator : public std::iterator<std::bidirectional_iterator_tag, const value_type> {
/* same with const ... */
};
/* More typedefs... */
typedef ListIterator iterator;
typedef ConstListIterator const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef typename std::iterator_traits<iterator>::difference_type difference_type;
protected:
/* Class members */
Node* root; // at the end
size_type elementCount;
public:
/* functions... */
iterator insert(const_iterator position, const value_type& val);
iterator insert(const_iterator position, size_type n, const value_type& val);
template<class InputIterator>
iterator insert(const_iterator position, InputIterator first, InputIterator last);
iterator insert(const_iterator position, value_type&& val);
iterator insert(const_iterator position, std::initializer_list<value_type> il);
/* more functions... */
};
And the declaration of the function :
template <class T>
template <class InputIterator>
inline typename List<T>::iterator List<T>::insert(const_iterator position, InputIterator first, InputIterator last)
{
/* i don't know how to deal with the InputIterator */
value_type a(*first); // Illegal indirection
iterator it(first); // not working
}
Any help is welcome

writing a map as template with Pair and iterator c++

A little help please with this task, I need to write a simplified map template with Pair class and iterator class, I'm a beginner and I'm really messy and troubled with this, I would be glad for some help only with the header.
#include <cassert>
#include <functional>
#include "Exceptions.h"
template <typename DataType>
struct Node {
DataType data;
Node<DataType> *next;
};
namespace mtm {
template <class KeyType, class ValueType, class CompareFunction = std::less<KeyType> >
class MtmMap {
public:
class Pair {
public:
Pair(const KeyType& key, const ValueType& value)
: first(key), second(value){}
const KeyType first;
ValueType second;
~Pair() = default;
Pair* begin();
Pair* end();
void insert();
void insert(const KeyType&, const ValueType&);
void remove(const KeyType&);
bool containsKey(const KeyType& key) const;
int size() const;
Pair& operator=(const Pair&) = default;
ValueType& operator[](const KeyType&);
const ValueType& operator[](const KeyType&) const;
Pair& operator[]();
/*private:
Node<Pair> _pairs;
int _size;
*/
};
class iterator{
/*private:
Pair *cur_itr;
Node<Pair*> pair_ptr;
*/
public:
iterator();
iterator(const Pair*);
iterator(const iterator&);
~iterator();
iterator& operator=(const iterator&) = default;
iterator& operator++(int);
iterator& operator++();
iterator& operator*();
bool operator==(const iterator&);
};
bool operator!=(const iterator&, const iterator&);
};
}
I was given an empty part, like this:
#include <cassert>
#include <functional>
#include "Exceptions.h"
namespace mtm {
template <class KeyType, class ValueType, class CompareFunction = std::less<KeyType> >
class MtmMap {
public:
class Pair {
public:
Pair(const KeyType& key, const ValueType& value)
: first(key), second(value) {}
const KeyType first;
ValueType second;
};
};
}
And the first part is after I wrote all the needed for realization operators and functions. Notice that it is pretty simplified version of map container, so I only need this part, WITHOUT USING ANY STL.
Can somebody help with writing the private fields and other things that belongs to the structure of the template class MtmMap ???
The idea using a list struct is mine, as I need list of operators and pairs as a container, as I can see it.
Any other ideas, comments, and stuff will be excellent and I'll be grateful, thanks a lot.
EDIT:
Just to clarify my question, before I'll continue to the cpp file for realization, I'm stuck, because I don't understand how I should realize all the functions of the map, how to storage them and etc.
I need help finishing this header.

Implementing a nested class function in c++

so thats what i got going.
template<class T>
class List{
Node<T> head;
int size;
public:
class Iterator;
template <class T>
class List<T>::Iterator{
public:
Iterator& operator++();
i'm trying to implement like so:
template<class T>
typename List<T>::Iterator& List<T>::Iterator::operator++()
but it keeps telling me "Member declaration not found"
EDIT:
thats the entire relevent code:
template <class T>
class Node {
T data;
Node<T>* next;
public:
Node () : next(0){};
Node (const T& info, Node<T>* next = 0) : data(info), next(next){};
friend class List<T>;
friend class Iterator;
friend class ConstIterator;
};
template<class T>
class List{
Node<T> head;
int size;
void listSwap(Node<T>* node1, Node<T>* node2);
public:
class Iterator;
class ConstIterator;
List ();
List(const List<T>& list);
List& operator=(const List<T>& list);
ConstIterator begin() const;
Iterator begin();
ConstIterator end() const;
Iterator end();
void insert(const T& t);
void insert(const T& t,const Iterator& it);
void remove(const Iterator& it);
// template<class Function>
// ConstIterator find(Function f);
template<class Function>
Iterator find(Function f);
template<class Function>
void sort(Function f);
int getSize();
bool operator==(const List<T>& list2) const;
bool operator!=(const List<T>& list2) const;
~List();
};
template <class T>
class List<T>::Iterator{
List<T>* list;
Node<T>* index;
public:
Iterator(List<T> list);
Iterator(List<T> list, Iterator& it);
Iterator& operator++();
Iterator operator++(int);
T operator*();
bool operator==(const Iterator& iterator2);
bool operator!=(const Iterator& iterator2);
~Iterator();
friend class List<T>;
};
thought I think it is ok :/
so frustrating sometimes....
Thank you guys for the help!
You don't need template<class T> class List<T>::Iterator in the Iterator class definition if iterator is a nested class. Just class Iterator.
template<class T>
class List{
Node<T> head;
int size;
public:
class Iterator
{
public:
Iterator& operator++();
....
};
....
};
Either that, or you are missing the closing }; of your List class:
template<class T>
class List{
Node<T> head;
int size;
public:
class Iterator;
};
^^ HERE!
I see some obvious bugs, as the class List is not closed before you define List<T>::Iterator, but I presume it is so because you cut off some portion of your code.
Unfortunately, I was unable to reproduce your case. The following code:
class List {
int size;
public:
class Iterator;
};
template <class T>
class List<T>::Iterator {
public:
Iterator& operator++();
};
template <class T>
typename List<T>::Iterator& List<T>::Iterator::operator++() {
return *this;
}
int main() {
}
And it compiles just fine under g++ (4.6.3) and clang++ (3.1), so the problem is somewhere else which you are not showing us.
You first code sample seems to be shreeded beyond recognition.
As for your second (longer) section of code, I don't see anthing wrong with it aside from one suspect area. Your friend declarations inside Node will refer to some non-template Iterator and ConstIterator classes from global namespace. Meanwhile, Iterator and ConstIterator from List are templates that do not belong to global namespace. Were those friend declarations in Node supposed to refer to Iterator and ConstIterator from List or not?