
#include <iostream>
using namespace std;

template<typename T>
class list
{
	struct element {
		element* next;
		T value;

		element(T val) {
			value = val;
		}
	};


	element* head;

	void init() {
		head = nullptr;
	}

public:
	/*
	 * Iterator. Basically a wrapped pointer that supports the common
	 * iterator interface -- operator++, comparison iterators, and
	 * dereference by prefix *.
	 */
	class iterator {
		element *p;
	public:
		iterator(element *ptr) {
			p = ptr;
		}
		bool operator==(const iterator &q) {
			return p == q.p;
		}
		bool operator!=(const iterator &q) {
			return p != q.p;
		}
		iterator& operator++(){
			p = p->next;
			return *this;
		}

		T& operator*() {
			return p->value;
		}
	};
	list() {
		init();
	}

	list(const list& a) {
		init();
		element *i;
		for (i = a.head; i; i = i->next)
			push(i->value);
	}

	~list() {
		clear();
	}

	void clear() {
		while (!empty()) pop();
	}

	void push(const T& val) {
		element *newEl = new element(val);
		newEl->next = head;
		head = newEl;
	}

	bool empty() const {
		return !head;
	}

	// don't use this on empty list
	//there will be UB.
	T& front() const {
		return head->value;
	}

	void pop() {
		element *p = head->next;
		delete head;
		head = p;
	}

	list& operator= (const list& a) {
		clear();

		element *i;
		for (i = a.head; i; i = i->next)
			push(i->value);
		return *this;
	}

	/*
	 * This creates accompanying iterators from a list object.
	 * In realsitic setting, you should also create constant variants of
	 * the iterators, so that iterating through const list is supported as
	 * well.
	 */
	iterator begin() {
		return iterator(head);
	}

	iterator end() {
		return iterator(nullptr);
	}
};

template <typename T>
list<T> create_list()
{
	list<T> r;
	r.push(5);
	r.push(6);
	return r;
}

template <typename T>
void print_out_list(list<T> l)
{
	while (!l.empty()) {
		cout << l.front() << endl;
		l.pop();
	}
}

template <typename T>
ostream& operator<<(ostream& o, list<T>&l) {
	o << "(list";
	for (auto&i : l) cout << ' ' << i;
	o << ')';
	return o;
}


int main()
{
	list<int> l = create_list<int>();

	/* 
	 * The main result, our custom list behaves like any other iterable object!
	 */
	for (auto&i : l) cout << i << endl;
	cout << l << endl;

	return 0;
}


