Skip to content

Instantly share code, notes, and snippets.

@ongamex
Created August 15, 2014 21:59
Show Gist options
  • Save ongamex/45244796d9cc73956008 to your computer and use it in GitHub Desktop.
Save ongamex/45244796d9cc73956008 to your computer and use it in GitHub Desktop.
Events
// variadic.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <vector>
#include <memory>
#include <iostream>
#include <functional>
#include <algorithm>
template<class... Args>
class Event;
//----------------------------------------------------------------------------
template<class... Args>
class IDelegate
{
friend class Event<Args...>;
public :
IDelegate() : event(nullptr) {}
virtual ~IDelegate() {}
bool is_subscribed() const { return event != nullptr; }
Event<Args...>* get_event() const { return event; }
//user defined
virtual bool operator() (Args... args) = 0;//returns true if unsubscription will be performed
virtual void on_unsubscribe() {};
private :
void subscribe(Event<Args...> *evt) {event = evt;}
void unsubscribe();
Event<Args...> *event;
};
//----------------------------------------------------------------------------
template<class... Args>
class Event
{
public :
typedef std::shared_ptr<IDelegate<Args...> > DelegateSptr;
~Event()
{
for(auto i: m_delegates) if(i) i.reset();
m_delegates.clear();
}
void occur(Args... args)
{
auto new_end = std::remove_if(begin(m_delegates), end(m_delegates),
[&args...](DelegateSptr i) -> bool
{
if (i.get() == nullptr) return true;
if(i->operator()(args...))
{
i->on_unsubscribe();
return true;
}
return false;
}
);
m_delegates.erase(new_end, m_delegates.end());
}
void add_delegate(DelegateSptr delegate)
{
delegate->subscribe(this);
m_delegates.push_back(delegate);
}
std::vector<DelegateSptr> m_delegates;
};
template<class... Args>
void IDelegate<Args...>::unsubscribe() { event->remove_delegate(this); event = nullptr; }
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
enum class DamageType
{
Physical,
Magic,
Nature
};
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
struct TotalDamageDone: public IDelegate<int, DamageType>
{
static int damage;
virtual bool operator() (int dmg, DamageType type)
{
damage += dmg;
return false;
}
};
int TotalDamageDone::damage = 0;
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
struct TotalMagicDamageDone: public IDelegate<int, DamageType>
{
static int damage;
virtual bool operator() (int dmg, DamageType type)
{
if(type == DamageType::Magic)
damage += dmg;
return false;
}
};
int TotalMagicDamageDone::damage = 0;
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
struct IsNatureDamageDone: public IDelegate<int, DamageType>
{
bool Destroyed = false;
~IsNatureDamageDone()
{
std::cout <<"Destroyed\n";
Destroyed = true;
}
bool condition = false;
virtual bool operator() (int dmg, DamageType type)
{
if(type == DamageType::Nature) condition = true;
return condition;
}
virtual void on_unsubscribe()
{
std::cout << "Achievement unlocked: Use an ability that does Nature Damage!\n";
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Event<int, DamageType> take_damage_event;
take_damage_event.add_delegate(std::make_shared<TotalMagicDamageDone>());
take_damage_event.add_delegate(std::make_shared<TotalDamageDone>());
take_damage_event.add_delegate(std::make_shared<IsNatureDamageDone>());
take_damage_event.occur(10, DamageType::Physical);
take_damage_event.occur(15, DamageType::Magic);
take_damage_event.occur(1, DamageType::Nature);
std::cout << "Total damage delt: " << TotalDamageDone::damage << std::endl;
std::cout << "Total magic damage delt: " << TotalMagicDamageDone::damage << std::endl;
std::cin.get();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment