#include <iostream>

using namespace std;

template <class T>
struct funkyInt
{
  virtual int operator() ()=0;
};

template <class T>
struct funkyStack
{
  virtual int operator () (int)=0;
};

template <class T>
struct fint:funkyInt<T>
{
  int arg;
  fint(int _arg)
  {
    arg = _arg;
  }
  int operator () ()
  {
    return arg;
  }
};

template <class T>
struct fpush:funkyStack<T>
{
  funkyInt<T> * arg;
  funkyStack<T> * next;
  fpush(funkyInt<T> * _arg, funkyStack<T> * _next=0)
  {
    arg = _arg;
    next = _next;
  }
  int operator() (int i)
  {
    if (i != 0 && next != 0)
      return (*next)(i-1);
    return (*arg)();
  }
};

template <class T>
struct fpop:funkyStack<T>
{
  funkyStack<T> * next;
  fpop(funkyStack<T> * _next)
  {
    next = _next;
  }
  int operator () ()
  {
    return (*next)(0);
  }
  int operator () (int i)
  {
    return (*next)(i+1);
  }
};

template <class T>
struct functor
{
  T (*f) (T,T);
  funkyInt<T> * arg1;
  funkyInt<T> * arg2;
  functor(funkyInt<T>*_arg1, funkyInt<T>*_arg2,T (*_f)(T,T))
  {
    arg1 = _arg1;
    arg2 = _arg2;
    f = _f;
  }
  int operator () ()
  {
    return (*f)((*arg1)(),(*arg2)());
  }
};

int adde(int a, int b)
{
  return a+b;
}

int main()
{
  cout << "funky coding style\n";
  
  fint <int> cinq(5);
  fint <int> quatre(4);
  
  fpush <int> stack(&cinq);
  fpush <int> st2(&quatre,&stack);
  fpush <int> st3(&quatre,&st2);
  fpop <int> st4(&st3);
  fpop <int> st5(&st4);
  fpop <int> st6(&st5);
  cout << st6() << "\n";
  
  functor<int> un(&cinq,&quatre,&adde);
  cout << un() << '\n';
  
  return 0;
}
