#include <iostream>
using namespace std;

template<typename T>
void println(T data) {
	cout << data << endl;
}

template<typename T>
class List {
public:
	class Item {
	protected:
		T data;
		Item* prev;
		Item* next;
	public:
		Item(T data, Item* prev, Item* next) {
			this->data = data;
			this->prev = prev;
			this->next = next;
		}
		T* getData() {
			return &data;
		}
		Item* getNext() {
			return next;
		}
		Item* getPrev() {
			return prev;
		}
	};
private:
	class ExtendedItem : Item {
	public:
		void setPrev(Item* prev) {
			this->prev = prev;
		}
		void setNext(Item* next) {
			this->next = next;
		}
		void removeSelf() {
			if (next)
				((ExtendedItem*)next)->setPrev(prev);
			if (prev)
				((ExtendedItem*)prev)->setNext(next);
		}
	};
	Item* first;
	Item* last;
public:
	List() {
		println("Default constructor called");
		first = NULL;
		last = NULL;
	}
	List(List<T>& other) {
		println("Copy constructor called");
		first = NULL;
		last = NULL;
		for (Item* cur = other.getFront(); cur != NULL; cur = cur->getNext()) {
			pushBack(*cur->getData());
		}
	}
	~List() {
		println("Destructor called");
		while (first != NULL) {
			Item* next = first->getNext();
			// ((ExtendedItem*)first)->removeSelf();
			delete first;
			first = next;
		}
	}
	Item* pushFront(T data) {
		Item* newOne = new Item(data, NULL, first);
		if (first != NULL)
			((ExtendedItem*)first)->setPrev(newOne);
		first = newOne;
		if (last == NULL)
			last = newOne;
		return newOne;
	}
	Item* pushBack(T data) {
		Item* newOne = new Item(data, last, NULL);
		if (last != NULL)
			((ExtendedItem*)last)->setNext(newOne);
		last = newOne;
		if (first == NULL)
			first = newOne;
		return newOne;
	}
	Item* getFront() {
		return first;
	}
	Item* getBack() {
		return last;
	}
	void remove(Item* element) {
		if (element == NULL)
			return;
		((ExtendedItem*)element)->removeSelf();
		if (element == first)
			first = first->getNext();
		if (element == last)
			last = last->getPrev();
		delete element;
	}
	template <typename C, bool Pred(T*, C)>
	Item* find(C context) {
		for (Item* cur = first; cur != NULL; cur = cur->getNext())
			if (Pred(cur->getData(), context))
				return cur;
		return NULL;
	}
};

List<size_t>& newList(size_t a) {
	List<size_t> result;
	result.pushBack(a);
	return result;
}

int main() {
	List<size_t> a = newList(1);
	for (List<size_t>::Item* cur = a.getFront(); cur != NULL; cur = cur->getNext())
		println(*cur->getData());
	return 0;
}