#ifndef __CALLBACK_HPP #define __CALLBACK_HPP #include #include #include #include #include namespace fibre { namespace detail { template struct get_default { static T val() { return {}; } }; template<> struct get_default { static void val() {} }; } template class Callback { public: Callback() : cb_(nullptr), ctx_(nullptr) {} Callback(std::nullptr_t) : cb_(nullptr), ctx_(nullptr) {} Callback(TRet(*callback)(void*, TArgs...), void* ctx) : cb_(callback), ctx_(ctx) {} /** * @brief Creates a copy of another Callback instance. * * This is only works it the other callback has identical template parameters. * This constructor is templated so that construction from an incompatible * callback gives a useful error message. */ //template //Callback(const Callback& other) : cb_(other.cb_), ctx_(other.ctx_) { // static_assert(std::is_same, Callback>::value, "incompatible callback type"); //} Callback(const Callback& other) : cb_(other.cb_), ctx_(other.ctx_) {} // If you get a compile error "[...] invokes a deleted function" that points // here then you're probably trying to assign a Callback with incompatible // template arguments to another Callback. template Callback(const Callback& other) = delete; /** * @brief Constructs a callback object from a functor. The functor must * remain allocated throughout the lifetime of the Callback. */ template Callback(const TFunc& func) : cb_([](void* ctx, TArgs...args){ return (*(const TFunc*)ctx)(args...); }), ctx_((void*)&func) {} operator bool() { return cb_; } TRet invoke(TArgs ... arg) const { if (cb_) { return (*cb_)(ctx_, arg...); } return detail::get_default::val(); } TRet invoke_and_clear(TArgs ... arg) { void* ctx = ctx_; auto cb = cb_; ctx_ = nullptr; cb_ = nullptr; if (cb) { return (*cb)(ctx, arg...); } return detail::get_default::val(); } typedef TRet(*cb_t)(void*, TArgs...); cb_t get_ptr() { return cb_; } void* get_ctx() { return ctx_; } private: TRet(*cb_)(void*, TArgs...); void* ctx_; }; template struct function_traits { using TRet = _TRet; using TArgs = std::tuple<_TArgs...>; using TObj = _TObj; }; template function_traits<_TRet, _TObj, _TArgs...> make_function_traits(_TRet (_TObj::*)(_TArgs...)) { return {}; } template struct MemberCallback; template struct MemberCallback> { using cb_t = Callback; static cb_t with(TObj* obj) { return cb_t{[](void* obj, TArgs... arg) { return (((TObj*)obj)->*func)(arg...); }, obj}; } }; template> typename MemCb::cb_t make_callback(typename TTraits::TObj* obj) { return MemCb::with(obj); } #define MEMBER_CB(obj, func) \ fibre::make_callback< \ decltype(&std::remove_reference_t::func), \ &std::remove_reference_t::func \ >(obj) } #endif // __CALLBACK_HPP