Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // main.cpp
- #include <iostream>
- #include <unordered_map>
- #include <functional>
- #include <typeinfo>
- #include <typeindex>
- #include <type_traits>
- #include "function_traits.h"
- class Event
- {
- public:
- virtual ~Event()
- {}
- protected:
- Event() = default;
- };
- class TestEvent : public Event
- {};
- class EventDispatcher
- {
- public:
- template<class F>
- void Register( F&& f )
- {
- // this static assert seems to always fail
- //static_assert(std::is_invocable<F>::value,"Handler must be invocable.");
- using Traits = function_traits<F>;
- static_assert(Traits::arity == 1,"Handler must have exactly 1 parameter.");
- using PCRef = typename Traits::template argument<0>::type;
- using PC = typename std::remove_reference<PCRef>::type;
- using P = typename std::remove_const<PC>::type;
- static_assert(std::is_base_of<Event,P>::value && !std::is_same<Event,P>::value,"Handler parameter must be derived from Event.");
- static_assert(std::is_reference<PCRef>::value,"Handler parameter must be passed by reference.");
- static_assert(std::is_const<PC>::value,"Handler parameter must be constant reference.");
- // wrap f in a lambda that casts to specific event handled
- handlers[typeid(P)] = [f]( const Event& e )
- {
- f( static_cast<const P&>(e) );
- };
- }
- void Dispatch( const Event& e ) const
- {
- auto i = handlers.find( typeid(e) );
- if( i != handlers.end() )
- {
- i->second( e );
- }
- }
- private:
- std::unordered_map<std::type_index,std::function<void(const Event&)>> handlers;
- };
- void FreeFunctionHandler( [[maybe_unused]] const TestEvent& e )
- {
- std::cout << "TestEvent fired; handled by free function." << std::endl;
- }
- int main()
- {
- constexpr bool using_lambda = true;
- EventDispatcher ed;
- if constexpr( using_lambda )
- {
- ed.Register([]( [[maybe_unused]] const TestEvent& e )
- {
- std::cout << "TestEvent fired; handled by lambda function." << std::endl;
- });
- }
- else
- {
- ed.Register( FreeFunctionHandler );
- }
- ed.Dispatch( TestEvent{} );
- return 0;
- }
- // function_traits.h
- #pragma once
- #include <tuple>
- template<class F>
- struct function_traits;
- // function pointer
- template<class R,class... Args>
- struct function_traits<R( *)(Args...)> : public function_traits<R( Args... )>
- {};
- template<class R,class... Args>
- struct function_traits<R( Args... )>
- {
- using return_type = R;
- static constexpr std::size_t arity = sizeof...(Args);
- template <std::size_t N>
- struct argument
- {
- static_assert(N < arity,"error: invalid parameter index.");
- using type = typename std::tuple_element<N,std::tuple<Args...>>::type;
- };
- };
- // member function pointer
- template<class C, class R, class... Args>
- struct function_traits<R(C::*)(Args...)> : public function_traits<R(C&,Args...)>
- {};
- // const member function pointer
- template<class C, class R, class... Args>
- struct function_traits<R(C::*)(Args...) const> : public function_traits<R(C&,Args...)>
- {};
- // member object pointer
- template<class C, class R>
- struct function_traits<R(C::*)> : public function_traits<R(C&)>
- {};
- // functor
- template<class F>
- struct function_traits
- {
- private:
- using call_type = function_traits<decltype(&F::type::operator())>;
- public:
- using return_type = typename call_type::return_type;
- static constexpr std::size_t arity = call_type::arity - 1;
- template <std::size_t N>
- struct argument
- {
- static_assert(N < arity,"error: invalid parameter index.");
- using type = typename call_type::template argument<N + 1>::type;
- };
- };
- template<class F>
- struct function_traits<F&> : public function_traits<F>
- {};
- template<class F>
- struct function_traits<F&&> : public function_traits<F>
- {};
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement