I'm trying to create my own implementation of a doubly-linked list for learning purpose. I wanted to use a template class to do this. I have a few constructors that have the definition like this:
template <typename TYPE>
class DList {
public:
DList(const size_t size, const TYPE& val = TYPE());
template <typename ITER>
DList(ITER&& begin, ITER&& end);
};
(I have more code that I have omitted).
The first constructor copies the value provided size times (so DList<int>(5, 2) would copy the number 2, 5 times)
The second constructor copies a range (between 2 Iterators) in to the list. (so DList<int>(other.begin(), other.end()) would copy one data structure in to the DList)
The question is that how do I set the preference of the two constructors? For example if I'm instantizing my class with this line:
DList<int> listTest2(6, 2);
The compiler gets confused and chooses the iterator based constructor over the size constructor and throws errors. I want to keep the template iterator constructor because I have other classes like that one (that implements other data structures) and the iterators is a class inside the class. (so DList has a class inside it called iterator, see below for more info on what I mean).
Is there anyway to set a preference over which constructor gets called. I want it to work like how I can call std::vector<int>(other.begin, other.end) and std::vector<int>(2, 3) and both work.
I have attached the header file for my template class below:
template <typename TYPE>
class DList {
public:
struct Node {
Node* prev;
TYPE data;
Node* next;
};
class iterator {
public:
iterator();
iterator(const Node* node);
iterator(const iterator& it);
iterator& operator++(); // preincrement
iterator& operator--();
iterator operator++(int); // postincrement
iterator operator--(int);
iterator& operator=(const iterator& it);
iterator& operator-(int scale);
iterator& operator+(int scale);
bool operator==(const iterator& it);
TYPE& operator*();
TYPE& operator->();
Node* getNode();
private:
Node* data;
};
DList();
DList(const DList& other);
DList(const size_t size, const TYPE& val = TYPE());
template <typename ITER>
DList(ITER&& begin, ITER&& end);
iterator begin() const;
iterator end() const;
void clear();
void push_back(const TYPE& val);
void push_front(const TYPE& val);
void pop_back();
void pop_front();
void insert(size_t idx, const TYPE& val);
void insert(const DList<TYPE>::iterator it, const TYPE& val);
void remove(const TYPE& val);
size_t size() const;
const TYPE& operator[](size_t idx) const;
TYPE& operator[](size_t idx);
private:
Node* mHead; /// #todo convert to iterators?
Node* mTail;
size_t mSize;
};
First of all: observe that with
DList<int> listTest2(6, 2);
you call the wrong constructor because you pass the wrong first argument: the size/val contructor wait for a std::size_t for the first parameter, so an unsigned value. But you send 6, that is a signed value.
The right way to call the size/val constructor is
DList<int> listTest2(6U, 2);
Second; you use && (rvalue) references; so you can use C++11; so you can use decltype.
Not a great solution but if you really want that DList<int> (6, 2) call the size/val constructor, you can use SFINAE and enable the template constructor only when ITER typename support the unary * operation (access to pointed value, supported by iterators but not by simple integers), so
template <typename I, typename = decltype(*I{})>
DList (I && begin, I && end)
The following is a full working (minimal) example
#include <iostream>
#include <vector>
template <typename T>
struct DList
{
DList (std::size_t const size, T const & val = T{})
{ std::cout << "constructor 1" << std::endl; }
template <typename I, typename = decltype(*I{})>
DList (I && begin, I && end)
{ std::cout << "constructor 2" << std::endl; }
};
int main()
{
std::vector<int> vi { 2, 3, 5, 7, 11, 13 };
DList<int>(6, 2); // print constructor 1
DList<int>(vi.cbegin(), vi.cend()); // print constructor 2
}
Related
In my everlasting effort to implement a link list I created a class-template representing the container (CursorList) and I have a seperate class-template that is supposed to be my iterator (CursorIterator).
In my CursorList I use a struct Node to represent elements of the list. I want to share this struct with my CursorIterator-Class (the iterator is pointing towards a Node). However this doesn't work as I want it to, I can't really get both classes to know the structures of Node.
CursorList.h
#ifndef CURSORLIST_H
#define CURSORLIST_H
#include "CursorIterator.h"
template <class T> class CursorList {
public:
CursorList() {}
typedef T value_type;
typedef CursorIterator<T> iterator;
bool empty() const;
int size() const;
T& front() const;
void push_front(const T& item);
void pop_front();
iterator begin() const;
iterator end() const;
iterator insert(iterator itr, const T& value);
iterator erase(iterator start, iterator stop);
iterator erase(iterator itr);
struct Node {
Node(const T& n_data, Node* n_prev, Node* n_next): data(n_data), prev(n_prev), next(n_next) {}
T data;
Node* prev;
Node* next;
};
private:
Node* m_head;
};
#endif //CURSORLIST_H
CursorIterator.h
#ifndef CURSORITERATOR_H
#define CURSORITERATOR_H
template <class T> class CursorIterator {
private:
typedef CursorIterator<T> iterator;
Node* m_rep;
public:
CursorIterator() {}
CursorIterator(Node* n): m_rep(n) {}
T& operator *();
iterator& operator = (const iterator& rhs);
bool operator != (const iterator& rhs) const;
bool operator == (const iterator& rhs) const;
iterator& operator ++();
iterator operator ++(int);
};
#endif //CURSORITERATOR_H
I'm almost done with the implementation of a std::vector type of vector (hopefully) but I'm having a little bug in the code and I can't seem to find where. Basically when I build Vector and use push_back, the vector automatically allocates new memory for more elements (specifically twice the size of the vector) but when doing so, the "extra space" is initialized to 0's and I don't know why.
Here is my code:
Vector.h
#include <memory>
#include <cstddef>
template <class T>
class Vec{
public:
typedef T* iterator;
typedef const T* const_iterator;
typedef size_t size_type;
typedef T value_type;
Vec(){create();}
Vec(size_type n, const T& val = T()) {create(n, val);}
~Vec() {uncreate();}
//copy constructor
Vec(const Vec& v) {create(v.begin(), v.end());}
//assignment operator
Vec& operator=(const Vec&);
size_type size() const {return limit - data;}
//index operators
T& operator[](size_type i) {return data[i];}
const T& operator[](size_type i) const {return data[i];}
iterator begin() {return data;}
const_iterator begin() const {return data;}
iterator end() {return limit;}
const_iterator end() const {return limit;}
void push_back(const T&);
private:
iterator data; //1st element
iterator avail; //one past last constructed element
iterator limit; //one past last available element
//Memory management
std::allocator<T> alloc;
void create();
void create(size_type, const T&);
void create(const_iterator, const_iterator);
void uncreate();
void grow();
void unchecked_append(const T&);
};
template <class T>
void Vec<T>::push_back(const T& val){
if(avail == limit)
grow();
unchecked_append(val);
}
template <class T>
Vec<T>& Vec<T>::operator=(const Vec& rhs){
//self-assign
if(&rhs != this){
uncreate;
create(rhs.begin(), rhs.end());
}
return *this;
}
// Empty Vector, pointers to 0
template <class T> void Vec<T>::create(){
data = avail = limit = 0;
}
// Allocate memory for (size)
template <class T> void Vec<T>::create(size_type n, const T& val){
data = alloc.allocate(n); // returns pointer to first element
limit = avail = data +n;
std::uninitialized_fill(data, limit, val);
}
template <class T> void Vec<T>::create(const_iterator i, const_iterator j){
data = alloc.allocate(j-i);
limit = avail =std::uninitialized_copy(i, j, data);
}
template <class T> void Vec<T>::uncreate(){
if(data){
iterator it = avail;
while(it != data)
alloc.destroy(--it);
// Free space
alloc.deallocate(data, limit - data);
}
// Empty Vector
data = limit = avail = 0;
}
template <class T> void Vec<T>::grow(){
// Allocate twice the space we had
size_type new_size = std::max(2 * (limit - data), ptrdiff_t(1));
// Allocate new space and copy to new space
iterator new_data = alloc.allocate(new_size);
iterator new_avail = std::uninitialized_copy(data, avail, new_data);
// Return old space used
uncreate();
// Reset pointers to point to new space
data = new_data;
avail = new_avail;
limit = data + new_size;
}
template <class T> void Vec<T>::unchecked_append(const T& val){
alloc.construct(avail++, val);
}
And this is how I created the vector
main.cpp
#include "vector.h"
#incude <iostream>
using namespace std;
int main(){
Vec<int> v1;
v1.push_back(12);
v1.push_back(9);
v1.push_back(74);
v1.push_back(22);
Vec<int> v2 = v1;
v2.push_back(70); //After doing this the vector is (12, 9, 74, 22, 70, 0, 0, 0)
for(auto e: v2) cout << e << " ";
cout << endl;
}
Thanks for any help and also any feedback on the actual code is appreciated. :)
The problem is (i do not know if it is really problem)
template <class T> void Vec<T>::grow(){
// Allocate twice the space we had
size_type new_size = std::max(2 * (limit - data), ptrdiff_t(1));
....
....
}
No need to do any vector copy to reproduce your problem.
The problem can be seen even in first vector after inserting 5th elemnt
v1.push_back(12);
v1.push_back(9);
v1.push_back(74);
v1.push_back(22);
v1.push_back(22); //5th elemnt.
now printing the size;
cout<<v1.size()<<endl; - it says 8.
Even the std vector, after resize(), it is normal behavior to print zeros for the empty elements.
Look at this example:
http://en.cppreference.com/w/cpp/container/vector/resize
if you do not want additional zeros, you have to tweak your ":new_size" calculation.
I'm not sure how much this fits in here and I'm kinda new to C++ but I have to make an ADT over a dynamic array/linked list with iterators. My question is, is there a way to make this iterator a template so it could work for both the dynamic array and the linked list or I have to make 2 different implementations for a class Iterator?
I was thinking of something like this:
template<typename Container>
class Iterator {
private:
Container *cont;
int pos;
public:
Iterator();
Iterator(const Container& c);
~Iterator();
bool isValid();
void operator++();
void operator--();
Element getCurrent();
};
Now clearly, it has no idea what Element is and that's my problem. Is there any way to have getCurrent() to return the element from the current position?
Is this going anywhere?
in c++ 14 you can do this :
template<typename Container>
class Iterator {
private:
Container *cont;
int pos;
public:
Iterator();
Iterator(const Container& c);
~Iterator();
bool isValid();
void operator++();
void operator--();
auto getCurrent(); // the return type is automatically generated
};
but in c++11
you have to erase the return type
so getCurrent(); must return a void *
and use reinterpret_cast(getCurrent());
implementation correction: (what i think)
template<typename Container>
class Iterator {
private:
Container *cont;
int currentPos;
int beginPos;
int endPos;
public:
Iterator();
Iterator(const Container& c,int endpos)currentPos{0},beginPos{0},endPos{endpos};
~Iterator();
void operator++();
void operator--();
auto& getCurrent()const;
}
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?