#include <iostream>
#include <memory>

struct function
{
    struct base
    {
	virtual void call() = 0;
	virtual base* clone() = 0;
    };

    template <typename Fn>	
    struct impl : base
    {
    	Fn fn_;
    	
	impl(Fn&& fn) : fn_(std::forward<Fn>(fn)){}
    	impl(Fn& fn) : fn_(fn){}
    	
	virtual void call()
	{
	   fn_();
	}
	
	virtual base* clone() { return new impl<Fn>(fn_); }
	
    };
    
    base* holder_;
    
    function() : holder_(nullptr)
    {};
    
    template <typename Fn>
    function(Fn&& fn) : holder_(nullptr)
    {

	holder_ = new impl<Fn>(std::forward<Fn>(fn));
    }
    
    function( function&& other)
    {
	holder_ = other.holder_;
	other.holder_ = nullptr;
	
    }
    
    function(const function& other)
    {
    	holder_ = other.holder_->clone();
    }
    ~function()
    {
    	if (holder_) delete holder_;
    }
    
    
    function& operator=(function&& other)
    {
	if (holder_) delete holder_;
	holder_ = other.holder_;
	other.holder_ = nullptr;
	return *this;
    }
    
    function& operator=(const function& other)
    {
	if (holder_) delete holder_;
	holder_ = other.holder_->clone();

	return *this;
    }
    
    void operator()()
    {
    	holder_->call();
    }
};


class Gpio
{
  public:
    using ExtiHandler = function;   
  //private:
    ExtiHandler handler;    
  //public:
    void enable_irq(ExtiHandler handler_in) 
    { 
      // enable interrupt
      // ...
      // save handler so callback can be issued later
      handler = handler_in;
    }
    

    
};

class Button
{
  private:
    Gpio& pin;    
  public:
    Button(Gpio& pin_in) : pin(pin_in) 
    {
    };

    void button_pressed()
    {
      std::cout << "Button pressed" << std::endl;
    }

    void init()
    {
      pin.enable_irq([this]() { this->button_pressed(); });
    }
    

};

int main() {
	Gpio some_pin;
	Button b(some_pin);
	b.init();
	
	some_pin.handler();
	return 0;
}