I'll preface this by saying I am mostly working off of examples written by others, so my understanding of template classes and friend classes is subpar. I am trying to write a circular list class:
#ifndef CIRCLIST_H
#define CIRCLIST_H
#include <cstdlib>
#include <iostream>
using namespace std;
template <class T>
class Node
{
public:
Node() : next(NULL), prev(NULL) {}
Node(const T& v) : value(v), next(NULL), prev(NULL) {}
T value;
Node<T>* next;
Node<T>* prev;
};
template <class T> class circList; //Forward declaration
template <class T>
class circIterator
{
public:
circIterator() : ptr(NULL) {}
~circIterator() {}
T& operator*() { return ptr->value; }
circIterator<T> & operator=(const circIterator<T> & old) { ptr = old.ptr; return *this; }
circIterator<T> & operator++() { ptr = ptr->next; return *this; }
circIterator<T> & operator--() { ptr = ptr->prev; return *this; }
friend class circList<T>;
friend bool operator==(const circIterator<T>& l, const circIterator<T>& r) { return l.ptr == r.ptr; }
friend bool operator!=(const circIterator<T>& l, const circIterator<T>& r) { return l.ptr != r.ptr; }
private:
Node<T>* ptr;
};
template <class T>
class circList
{
//class circIterator;
public:
circList() : entry(NULL), vsize(0) {}
~circList() {}
unsigned int size() const {return size;}
typename circList<T>::template circIterator<T> add(T const& v, circIterator<T> itr);
private:
Node<T>* entry;
unsigned int vsize;
};
template <class T>
typename circList<T>::template circIterator<T> circList<T>::add(T const& v, circIterator<T> itr)
{...}
When I write a simple main.cpp which simply declares a circList, I get the error:
error: no class template named 'circIterator' in 'class circList<int>'
The error references the last line, where the add function is implemented. What exactly does this mean? Does it mean that somewhere I have to code how an circIterator should "belong" to an circList? I really have no idea.
The error is caused by the fact that in circList<T>::template you are trying to access an identifier template (which is a keyword) that is not set for the class.
Just define the function as:
template <class T>
circIterator<T> circList<T>::add(T const& v, circIterator<T> itr) {...}
and declare it as:
circIterator<T> add(T const& v, circIterator<T> itr);
And here is the working example.
Related
trying to make chained list iterator
headerfile(20112310_3.h)
#include<iostream>
template<typename T> class Chain;
template<typename T>
class ChainNode{
friend class Chain<T>;
private:
T data;
ChainNode<T> *link;
};
template<typename T>
class Chain{
public:
Chain();
class ChainIterator{
ChainIterator(ChainNode<T> startNode=0);
T& operator*() const;
T* operator->() const;
ChainIterator& operator++();
ChainIterator operator++(int);
bool operator!=(const ChainIterator right) const;
bool operator==(const ChainIterator right) const;
private:
ChainNode<T>* current;
};
private:
ChainNode<T>* first;
};
and here's cpp file(20112310_3.cpp)
#include<iostream>
#include "20112310_3.h"
using namespace std;
template<typename T>
Chain<T>::Chain(){first=0;}
template<typename T>
Chain<T>::ChainIterator::ChainIterator(ChainNode<T> startNode){
current=startNode;
}
template<typename T>
T& Chain<T>::ChainIterator::operator*() const{
return current->data;
}
template<typename T>
T* Chain<T>::ChainIterator::operator->() const{
return ¤t->data;
}
template<typename T>
ChainIterator& Chain<T>::ChainIterator::operator++(){
current=current->link;
return *this;
}
template<typename T>
ChainIterator Chain<T>::ChainIterator::operator++(int){
ChainIterator old=*this;
current=current->link;
return old;
}
template<typename T>
bool Chain<T>::ChainIterator::operator!=(const ChainIterator right) const{
return current!=right.current;
}
template<typename T>
bool Chain<T>::ChainIterator::operator==(const ChainIterator right) const{
return current==right.current;
}
int main(void)
{
return 0;
}
when i try to compile this it gets error
20112310_3.cpp:26:1: error: ‘ChainIterator’ does not name a type
ChainIterator& Chain::ChainIterator::operator++(){
20112310_3.cpp:32:1: error: ‘ChainIterator’ does not name a type
ChainIterator Chain::ChainIterator::operator++(int){
how could i resolve this?
template<typename T>
ChainIterator& Chain<T>::ChainIterator::operator++() {
ChainIterator is not in scope yet when it is parsed. You have two solutions -- either qualify the full type:
template<typename T>
typename Chain<T>::ChainIterator& Chain<T>::ChainIterator::operator++() {
... or use a trailing return type, at which point ChainIterator is in scope.
template<typename T>
auto Chain<T>::ChainIterator::operator++() -> ChainIterator& {
I have an assignment in which I need to make template classes LinkedList and Traversible. Class Traversible needs to be a interface which declares functions for indexing and iteration of some collection class. I don't exactly know how to make an interface for iterator so LinkedList can use it. I was thinking something like
template <class T, class U>
class ITraversible {
public:
virtual U begin() noexcept = 0;
virtual U end() noexcept = 0;
virtual T& operator[](int) = 0;
};
and then in LinkedList header file I would do:
template <class T>
class LinkedList : public ITraversible<T,typename LinkedList<T>::iterator> {
struct node {
T data;
node* next, *prev;
explicit node(const T&);
void connect(node*);
};
node *head, *tail;
int n;
public:
/*************************ITERATOR************************/
class iterator : public std::iterator<std::bidirectional_iterator_tag, node*> {
typename LinkedList<T>::node* itr;
explicit iterator(node*) noexcept;
friend class LinkedList;
public:
iterator& operator++();
iterator operator++(int);
iterator& operator--();
iterator operator--(int);
bool operator==(const iterator&) const noexcept;
bool operator!=(const iterator&) const noexcept;
T& operator*() const noexcept;
T& operator->() const noexcept;
};
/**********************************************************/
LinkedList() noexcept;
LinkedList(std::initializer_list<T>);
LinkedList(const LinkedList&);
LinkedList(LinkedList&&) noexcept;
~LinkedList() noexcept;
LinkedList& operator=(LinkedList) noexcept;
template <class A>
friend void swap(LinkedList<A>&, LinkedList<A>&);
void add(const T&);
void removeAt(int);
int size() const noexcept;
bool operator==(const LinkedList&) const noexcept;
bool operator!=(const LinkedList&) const noexcept;
virtual T& operator[](int) override;
virtual iterator begin() noexcept override;
virtual iterator end() noexcept override;
};
But then Traversable template has two parameters and it should have only one.
Is this what I am supposed to do? Keep in mind I am new to templates and iterators.
When creating an interface you'll need to nail down the static types of what is being returned. These may behave dynamically different but you can't change the type other than using a subtype relation when returning pointers or references.
Personally, I think this exercise is ill-advised for a C++ context. It may make some sense when using Java or C#. However, similar behavior can be obtained. A rought sketch would be something like this (although this should work it will be rather slow):
template <typename T>
struct iterator_base {
virtual iterator_base() {}
virtual iterator_base<T>* do_clone() = 0;
virtual T& do_value() = 0;
virtual void do_next() = 0;
virtual bool do_equal() = 0;
// other operations to implement operator--, operator[], ...
};
template <typename It>
class iterator: iterator_base<typename std::iterator_traits<It>::value_type> {
typedef typename std::iterator_traits<It>::value_type> type;
It it;
iterator_base<type>* do_clone() { return new iterator<It>(*this); }
type& do_value() { return *this->it; }
void do_next() { ++this->it; }
bool do_equal(iterator_base<type>* other) {
return this->it == static_cast<iterator<It>>(other)->it;
}
};
template <typename T>
class poly_iterator {
std::unique_ptr<iterator_base<T>> ptr;
public:
poly_iterator(iterator_base<T>* ptr): ptr(ptr) {}
poly_iterator(poly_iterator const& other): ptr(other.ptr->clone()) {}
poly_iterator& operator= (poly_iterator other) {
other.swap(this);
return *this;
}
void swap(poly_iterator& other) { swap(this->ptr, other.ptr); }
T& operator*() { return this->ptr->value(); }
T* operator->() { return &this->operator*(); }
poly_iterator& operator++() { this->ptr->next(); return *this; }
poly_iterator operator++(int) {
poly_iterator rc(*this);
this->operator++();
return rc;
}
bool operator== (poly_iterator const& other) {
return this->ptr->equal(other.ptr.ptr());
}
bool operator!= (poly_iterator const& other) {
return !(*this == other);
}
// other operations
};
// define a suitable specialization of std::iterator_traits<poly_iterator<T>>
template <typename T>
class ITraversible {
virtual iterator_base<T>* do_begin() = 0;
virutal iterator_base<T>* do_end() = 0;
public:
poly_iterator<T> begin() { return this->do_begin(); }
poly_iterator<T> end() { return this->do_end(); }
// other operations
};
template <typename T>
class List: public ITraversible<T> {
std::list<T> list;
iterator_base<T>* do_begin() {
return iterator<std::list<T>::iterator>(list.begin());
}
iterator_base<T>* do_end() {
return iterator<std::list<T>::iterator>(list.end());
}
public:
// whatever is needed to fill the list
};
I have the following code:
template <class T>
class List {
public:
class Iterator;
class ConstIterator;
//Constructors and Destructors.
List() : head(NULL), tail(NULL), size(0) {}
List(const List& list);
~List();
//Methods
Iterator begin();
Iterator end();
void insert(const T& data);
void insert(const T& data, const Iterator& iterator);
void remove(const Iterator& iterator);
int getSize() const;
Iterator find();
void sort();
//Operators
List operator = (const List& list);
private:
class Node;
Node* head;
Node* tail;
int size;
};
template <class T>
class List<T>::Node
{
public:
//Constructors and destructors
Node(const T& _data, const Node* _next) : data(_data), next(_next) {}
~Node(); //Destructor
//Methods
//Operators
Node operator = (const Node& node);
private:
T data;
Node* next;
};
template<class T>
class List<T>::Iterator
{
public:
Iterator() : list(NULL), node(NULL){} //Constructor
Iterator(const Iterator& it) : list(it.list), node(it.node) {}
~Iterator(); //Destructor
Iterator& operator=(const Iterator& it);
T& operator * ();
T& operator ++ ();
T operator ++ (int);
T& operator -- ();
T operator -- (int);
bool operator == (const Iterator& iterator) const;
bool operator != (const Iterator& iterator) const;
private:
List<T>* list;
Node* node;
};
template<class T>
class List<T>::ConstIterator
{
public:
ConstIterator() : list(NULL), node(NULL){}
ConstIterator(const ConstIterator& it) : list(it.list), node(it.node) {}
~ConstIterator(); //Destructor
ConstIterator& operator=(const ConstIterator& it);
T& operator * ();
T& operator ++ ();
T operator ++ (int);
T& operator -- ();
T operator -- (int);
bool operator == (const ConstIterator& iterator) const;
bool operator != (const ConstIterator& iterator) const;
private:
const List<T>* list;
const Node* node;
};
template<class T>
Iterator List<T>::begin() {
return Iterator(this, head);
}
When I try to compile I get the following error:
error: expected constructor, destructor, or type conversion before ‘List’
On line:
Iterator List<T>::begin() {
I'm not sure what I'm doing wrong.
Iterator is not defined, but List<T>::Iterator is. You will also need to add typename:
template<class T>
typename List<T>::Iterator List<T>::begin() { ... };
Here, typename is required as an ambiguitator to tell the compiler that List<T>::Iterator is a type (rather than a static member). This is always required in the templated context (see here).
if you write the body of the function outside the class declaration, it should be:
typename List<T>::Iterator List<T>::begin() { ... }
edit: typename added
I write template class for binary tree:
template <class T>
class Tree {
public:
Tree():head_(NULL),size_(0){}
~Tree();
bool isEmpty()const {return size_ == 0;};
bool insert(const T& ele);
bool remove(const T& ele);
size_t size() {return size_;}
public:
class inorder_iterator
{
inorder_iterator& operator++ ();
private:
Node<T>* cur_;
};
}
What is the defintion for operator++?(I can`t compile using the following)
template <class T>
Tree<T>::inorder_iterator&
Tree<T>::inorder_iterator::operator++ ()
{
//....
}
With these changes it compiles:
template <class T>
class Node {};
template <class T>
class Tree {
Node<T> head_;
size_t size_;
public:
Tree():head_(NULL),size_(0){}
~Tree();
bool isEmpty()const {return size_ == 0;};
bool insert(const T& ele);
bool remove(const T& ele);
size_t size() {return size_;}
public:
class inorder_iterator
{
inorder_iterator& operator++ ();
private:
Node<T>* cur_;
};
};
template <class T>
typename Tree<T>::inorder_iterator&
Tree<T>::inorder_iterator::operator++ ()
{
//....
}
While attempting to provide an implimentation to this question, I got stuck on an error. I'm getting errors for 8 of my functions like this:
f:\code\utilities\hypergraph\hypergraph\hypergraph.h(233): error C2244: 'hypergraph::add_edge' : unable to match function definition to an existing declaration
f:\code\utilities\hypergraph\hypergraph\hypergraph.h(68) : see declaration of 'hypergraph::add_edge'
definition
'hypergraph::node_iter hypergraph::add_edge(void)'
existing declarations
'std::set::node*,ptr_cmp::node,P>,A>::const_iterator hypergraph::add_edge(void)'
for this class:
template<class T, class P>
struct ptr_cmp
: public std::binary_function<T, T, bool> {
P p_;
ptr_cmp(P p=P()) :p_(p) {}
bool operator()(const T* l, const T* r) const
{ return p_(*l, *r);}
};
template<class T, class P = std::less<T>, class A=std::allocator<T> >
class hypergraph {
typedef A sub_allocator;
public:
class node;
class edge;
typedef std::set<edge*, ptr_cmp<edge, std::less<edge> >, sub_allocator> edgeset;
typedef std::set<node*, ptr_cmp<node, P>, sub_allocator> nodeset;
typedef typename std::set<edge*, ptr_cmp<edge, std::less<edge> >, sub_allocator>::const_iterator edgeiter;
typedef typename std::set<node*, ptr_cmp<node, P>, sub_allocator>::const_iterator nodeiter;
class node { /*SNIP*/};
class edge { /*SNIP*/};
hypergraph(P pred=P(), A alloc=A());
nodeiter add_node(); /* beginning of 8 with the error */
nodeiter add_node(const T& rhs);
nodeiter add_node(T&& rhs);
nodeiter add_edge();
nodeiter erase(nodeiter iter);
nodeiter erase(node* iter);
nodeiter erase(edgeiter iter);
nodeiter erase(edge* iter); /* end of 8 with the error */
const nodeset& nodes() const;
const edgeset& edges() const;
A get_allocator() const;
protected:
hypergraph(const hypergraph& rhs);
hypergraph& operator=(const hypergraph& rhs);
A a_;
nodeset nodes_;
edgeset edges_;
unsigned int edgecount_;
};
And this function definition:
template<class T, class P, class A>
typename hypergraph<T,P,A>::node_iter hypergraph<T,P,A>::add_edge()
{
std::unique_ptr<edge> ptr = new edge(edgecount_++, sub_allocator(a_));
std::pair<edgeiter, bool> r = edges_.insert(ptr);
ptr.release();
return r.first;
}
I'm sure it's a stupid thing, but I can't figure out why MSVC10 can't match that prototype to that function.
And I think this code has an issue with const-ness, caused by containers of pointers, but I'll address that in a separate question.
Return value:
typename hypergraph<T,P,A>::node_iter
should be:
typename hypergraph<T,P,A>::nodeiter