#include <iostream>
#include <list>

#define __EVENTLISTENERBODY(_class_)                                                        \
	public: virtual ~_class_() {if (m_register) *m_register = false; m_register = nullptr;} \
	public: void __register(bool &reg) {m_register = &reg;}                                 \
	private: bool *m_register = nullptr;                                                    \
	
class EventResizeEventListener
{
	__EVENTLISTENERBODY(EventResizeEventListener);
public:
	virtual void Resize(uint32_t w, uint32_t h) = 0;
};

class EventKeyListener
{
	__EVENTLISTENERBODY(EventKeyListener);
public:
	virtual void Key(uint32_t key, bool press) = 0;
};

template<typename T, typename ... Args>
class EventSignal
{
	struct listData
	{
		void operator()(Args ...args) { (listener->*func)(args ...); }

		typedef void(T::*Func)(Args ...);
		T *listener = nullptr;
		Func func;
		bool active = false;		
	};

public:
	template <typename TypeU>
	void Connect(TypeU *listener, void(TypeU::*func)(Args ...))
	{
		if (!listener) return;
		listData data = { (T*)listener, (void(T::*)(Args...))func, true };
		m_lists.emplace_back(data);

		auto &it = m_lists.back();
		listener->T::__register(it.active);
	}

	void operator()(Args ...args) noexcept
	{
		for (auto i = m_lists.begin(); i != m_lists.end();)
		{
			if ((*i).active)
			{
				(*i)(args...);
				++i;
			}
			else
				i = m_lists.erase(i);
		}
	}

private:
	std::list<listData> m_lists;
};


class FooB : 
	public EventResizeEventListener, 
	public EventKeyListener
{
public:
	void Resize(uint32_t w, uint32_t h) final
	{
		std::cout << w << " " << h << std::endl;
	}

	void Key(uint32_t key, bool press) final
	{
		if (press)
			std::cout << key << " down" << std::endl;
		else
			std::cout << key << " up" << std::endl;
	}
};

int main() {
	FooB *fff = new FooB;

	EventSignal<EventResizeEventListener, uint32_t, uint32_t> sigResize;
	EventSignal<EventKeyListener, uint32_t, bool> sigKey;
		
	sigResize.Connect(fff, &FooB::Resize);
	sigKey.Connect(fff, &FooB::Key);

	sigResize(10, 20);
	sigKey(10, true);
	
	delete fff; fff = nullptr;
	
	sigResize(40, 50);
	sigKey(10, false);
	
	return 0;
}