#include <functional>
#include <memory>
#include <tuple>
#include <vector>
#include <type_traits>
#include <unordered_map>
#include <boost/any.hpp>

namespace s {
    
template<typename ... Types>
struct signal {
  using function_type = std::function<void(Types...)>;
  using tuple_type = std::tuple<Types...>;
};
    
template<typename T>
void* type_to_unique_value_helper() {
  static int dummy = 0;
  return static_cast<void*>(&dummy);
}
    
std::unordered_map<void*, std::vector<boost::any>>& signal_map() {
  static std::unordered_map<void*, std::vector<boost::any>> m;
  return m;
}

template<typename SIGNAL>
void bind(typename SIGNAL::function_type f) {
  signal_map()[type_to_unique_value_helper<SIGNAL>()].emplace_back(f);
}

template<typename SIGNAL, typename ... Types>
void emit(Types ... args) {
  static_assert(
      std::is_convertible<std::tuple<Types...>, typename SIGNAL::tuple_type>::value,
      "args unmatch");
  for(auto& f : signal_map()[type_to_unique_value_helper<SIGNAL>()]) {
    boost::any_cast<typename SIGNAL::function_type>(f)( args ... );
  }
}
}