#include <memory>
 
struct list_node_base {
  list_node_base(list_node_base *prev, list_node_base *next)
    : next(next), prev(prev) {}
  list_node_base *next;
  list_node_base *prev;
};
 
template <typename T>
class list {
  struct node : list_node_base {
    template <typename... Args>
    node(list_node_base *prev, list_node_base *next, Args&&... args)
      : list_node_base(prev, next), data(std::forward<Args>(args)...) {}
    T data;
  };
  list_node_base pointer_to_first;
  list_node_base* data() { return &pointer_to_first; }
 
public:
  list() : pointer_to_first(data(), data()) {}
 ~list() { clear(); }
 
  list(list const& o) =delete;
  list& operator=(list const& o) =delete;

  class iterator {
    friend class list;
    list_node_base *n;
    iterator (list_node_base *n) : n(n) {}
 
    node *as_node() noexcept { return static_cast<node*>(n); }
 
  public:
    typedef std::ptrdiff_t               difference_type;
    typedef std::forward_iterator_tag    iterator_category;
    typedef T                            value_type;
    typedef T*                           pointer;
    typedef T&                           reference;
 
    iterator& operator++()    { n = n->next; return *this; }
    iterator  operator++(int) { iterator tmp = *this; n = n->next; return tmp; }
 
    iterator& operator--()    { n = n->prev; return *this; }
    iterator  operator--(int) { iterator tmp = *this; n = n->prev; return tmp; }

    bool operator==(const iterator& o) const { return n == o.n; }
    bool operator!=(const iterator& o) const { return n != o.n; }
 
    T& operator* () { return  as_node()->data; }
    T* operator->() { return &as_node()->data; }
  };

  void clear()
  {
    for (iterator i=begin(); i!=end();)
      std::unique_ptr<node>(i++.as_node());
  }

  template <typename... Args>
  iterator emplace(iterator i, Args&&... args)
  {
    std::unique_ptr<node> n(new node(i.n->prev, i.n, std::forward<Args>(args)...));
    i.n->prev->next = n.get();
    i.n->prev       = n.get();
    return n.release();
  }
 
  iterator erase(iterator i)
  {
    std::unique_ptr<node> erased(i.as_node());
    erased->prev->next = erased->next;
    erased->next->prev = erased->prev;
    return erased->next;
  }
 
  iterator insert(iterator i, T const& x) { return emplace(i, x); }
  iterator insert(iterator i, T&& x)      { return emplace(i, std::move(x)); }
 
  iterator emplace_front(T const& x) { return emplace(begin(), x); }
  iterator push_front(T const& x)    { return emplace_front(x); }
  iterator push_front(T&&      x)    { return emplace_front(std::move(x)); } 
  void     pop_front() { erase(begin()); }  
  
  iterator emplace_back(T const& x) { return emplace(end(), x); }
  iterator push_back(T const& x)    { return emplace_back(x); }
  iterator push_back(T&&      x)    { return emplace_back(std::move(x)); }
  void     pop_back() { erase(data()->prev); }  

  iterator begin() { return data()->next; }
  iterator end()   { return data();       }
};
 
#include <iostream>
#include <iterator>
#include <cassert>
#include <string>
 
int main()
{
#define check(s) assert(std::string(l.begin(), l.end()) == s)

  list<char> l;
  l.push_back('m');  check("m");
  l.push_back('z');  check("mz");
  l.push_front('a'); check("amz");
  l.erase(l.begin());check("mz");
  l.insert(l.begin(), 'a');check("amz");
  l.insert(l.end(), '!');  check("amz!");
  l.pop_front();     check("mz!");
  l.pop_back();      check("mz");
  list<char>::iterator i=l.begin(); i++;
  i = l.insert(i, '-'); check("m-z");
  i = l.erase(i);       check("mz");
  l.erase(i);           check("m");
  l.push_front('a');    check("am");
  l.push_back('z');     check("amz");
  i=l.end(); i--; i--;
  i=l.erase(i);         check("az");
} 
