According to Why isn't argument deduction allowed in function return type?
When specifying a return type in a template class member function we have to be specific, for example: "the type std::vector isn't a type, std::vector<int> is."
So why do both of these examples compile? If I don't include the <T> in the first example, it shouldn't even be considered a type right?
template<typename T>
Queue<T>::Queue(const Queue& st) {}
template<typename T>
Queue<T>::Queue(const Queue<T>& st) {}
Given this template class
template<typename T>
class Queue {
private:
struct Node {
Node (T value) : value(value), next(nullptr) {}
Node (T value, Node* next) : value(value), next(next) {}
T value;
Node* next;
};
Node* head;
size_t sz;
void cleanList();
public:
Queue();
Queue(const Queue& st);
Queue& operator=(const Queue& st);
~Queue();
size_t size() const noexcept;
bool isEmpty() const noexcept;
T& front();
const Tt& front() const;
void enqueue(const T& elem);
void dequeue();
};
The reason these examples work is because of the injected class name. When you have
template<typename T>
some_type<T> some_type<T>::some_func(some_type)
the return type is not in scope of the class so you need to provide the template parameter. In the function parameter you are in the scope of the class and in the scope of the class some_type is injected as a name for some_type<T> so you don't need to use some_type<T>.
Related
Given that a class template called Queue with a nested class Node (not a class template):
template<typename T>
class Queue {
private:
struct Node {
Node (T value) : value(value), next(nullptr) {}
Node (T value, Node* next) : value(value), next(next) {}
T value;
Node* next;
};
Node* head;
size_t sz;
void cleanList();
public:
Queue();
Queue(const Queue& st);
Queue& operator=(const Queue& st);
~Queue();
size_t size() const noexcept;
bool isEmpty() const noexcept;
T& front();
const Tt& front() const;
void enqueue(const T& elem);
void dequeue();
};
I can do this:
template<typename T>
void Queue<T>::enqueue(const T& elem) {
Node* temp = new Node(elem);
}
It compiles, but why does declaring a Node not need more information? (like Queue::Node)
After reading Templates and nested classes/structures, all 3 of these also works and compiles:
template<typename T>
void Queue<T>::enqueue(const T& elem) {
typename LLQueue<Object>::Node* temp1 = new Node(elem);
LLQueue<Object>::Node* temp2;
LLQueue::Node* temp3;
}
Why do all versions work? Which is preferred when using a nested class in a class template?
It compiles, but why does declaring a Node not need more information?
This is how unqualified name lookup happens in a member function scope. First the compiler checks the scope of the function, doesn't find anything, and then moves on to the class scope. In the class scope it sees Node, so name lookup succeeds and you get the Node type that is a member of the class.
Why do all versions work?
C++ lets you be as explicit as you want to be. Any name can be fully qualified and that is what you are doing. With typename LLQueue<Object>::Node, the typename isn't needed, but it doesn't hurt anything. Its like doing struct foo{}; struct foo f; the struct isn't needed but it is allowed by the grammar. The second line with LLQueue<Object>::Node is just a less explicit way and also allowed since typename isn't actually required. LLQueue::Node works because in a class template class_name is injected into the class scope and it is class_name<template_params>.
Hello I have problems trying to overload the assignment operator in my generic linked-queue class.
Here is the code in question:
template<typename T>
class Queue : public IQueue<T>
{
(...)
public:
Queue();
Queue(const Queue<T> &origQueue);
virtual~Queue();
Queue& operator=(const Queue<T> &origQueue);
void enqueue(const T& element);
T dequeue();
T peek() const;
int size() const;
};
template<typename T>
Queue& Queue<T>::operator=(const Queue<T> &origQueue)
{
(...)
return *this;
}
Any ideas of where I'm going wrong?
Since your class is templated, you wanna return a Queue object, so the return value needs to be templated too:
template<typename T>
Queue<T>& Queue<T>::operator=(const Queue<T> &origQueue)
//...^
{
return *this;
}
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.
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
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?