Last active
December 22, 2025 14:30
-
-
Save xenobrain/ed90e8a54ad948cebf480fbbc3d0772b to your computer and use it in GitHub Desktop.
delegate
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef DELEGATE_H | |
| #define DELEGATE_H | |
| #if defined(_MSC_VER) | |
| #define DEBUG_BREAK __debugbreak() | |
| #else | |
| #include <csignal> | |
| #ifdef __EMSCRIPTEN__ | |
| #include <emscripten.h> | |
| #define DEBUG_BREAK EM_ASM({ debugger; }) | |
| #else | |
| #define DEBUG_BREAK raise(SIGTRAP) | |
| #endif | |
| #endif | |
| template<class T> struct IsVoid { static constexpr bool value = false; }; | |
| template<> struct IsVoid<void> { static constexpr bool value = true; }; | |
| template<> struct IsVoid<void const> { static constexpr bool value = true; }; | |
| template<> struct IsVoid<void volatile> { static constexpr bool value = true; }; | |
| template<> struct IsVoid<void const volatile> { static constexpr bool value = true; }; | |
| template <typename T> class Delegate; | |
| template <typename R, typename... Args> class Delegate<R(Args...)> { | |
| public: | |
| template <R(*function)(Args...)> auto bind() -> Delegate& { | |
| _instance = nullptr; | |
| _proxy = &function_proxy<function>; | |
| return *this; | |
| } | |
| template <class C, R(C::* function)(Args...)> auto bind(C* instance) -> Delegate& { | |
| _instance = instance; | |
| _proxy = &method_proxy<C,function>; | |
| return *this; | |
| } | |
| template <class C, R(C::*function)(Args...) const> auto bind(const C* instance) -> Delegate& { | |
| _instance = const_cast<C*>(instance); | |
| _proxy = &const_method_proxy<C,function>; | |
| return *this; | |
| } | |
| auto invoke(Args... args) const -> R { | |
| if (_proxy) { | |
| if constexpr (IsVoid<R>::value) { | |
| _proxy(_instance, static_cast<Args&&>(args)...); | |
| return; | |
| } else { | |
| return _proxy(_instance, static_cast<Args&&>(args)...); | |
| } | |
| } | |
| DEBUG_BREAK; | |
| if constexpr (IsVoid<R>::value) { | |
| return; | |
| } else { | |
| return R(); | |
| } | |
| } | |
| void clear() { | |
| _instance = nullptr; | |
| _proxy = nullptr; | |
| } | |
| explicit operator bool() const { return _proxy != nullptr; } | |
| private: | |
| typedef R(*proxy_function)(void*, Args...); | |
| template <R(*function)(Args...)> auto static function_proxy(void*, Args... args) -> R { | |
| return function(static_cast<Args&&>(args)...); | |
| } | |
| template <class C, R(C::* function)(Args...)> auto static method_proxy(void* instance, Args... args) -> R { | |
| return (static_cast<C*>(instance)->*function)(static_cast<Args&&>(args)...); | |
| } | |
| template <class C, R(C::* function)(Args...) const> auto static const_method_proxy(void* instance, Args... args) -> R { | |
| return (static_cast<const C*>(instance)->*function)(static_cast<Args&&>(args)...); | |
| } | |
| void* _instance{}; | |
| proxy_function _proxy{}; | |
| }; | |
| #endif // DELEGATE_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // pre-C++11 version | |
| //#include "Delegate.h" | |
| // C++11 version | |
| #include "delegate.h" | |
| #include <windows.h> | |
| void Func0(void) | |
| { | |
| } | |
| int Func1(int a) | |
| { | |
| return a + 10; | |
| } | |
| float Func2(float a, float b) | |
| { | |
| return a + b; | |
| } | |
| struct Test | |
| { | |
| void Func0(void) | |
| { | |
| } | |
| void Func0(void) const | |
| { | |
| } | |
| int Func1(int a) | |
| { | |
| return a + 20; | |
| } | |
| int Func1(int a) const | |
| { | |
| return a + 20; | |
| } | |
| float Func2(float a, float b) | |
| { | |
| return a + b; | |
| } | |
| float Func2(float a, float b) const | |
| { | |
| return a + b; | |
| } | |
| }; | |
| int main(void) | |
| { | |
| // delegate with zero arguments | |
| { | |
| typedef delegate<void(void)> TestDelegate; | |
| TestDelegate d; | |
| d.bind<&Func0>(); | |
| d.invoke(); | |
| } | |
| // delegate with one argument | |
| { | |
| typedef delegate<int(int)> TestDelegate; | |
| TestDelegate d; | |
| d.bind<&Func1>(); | |
| d.invoke(10); | |
| Test t; | |
| d.bind<Test, &Test::Func1>(&t); | |
| d.invoke(10); | |
| const Test ct; | |
| d.bind<Test, &Test::Func1>(&ct); | |
| d.invoke(10); | |
| } | |
| // delegate with two arguments | |
| { | |
| typedef delegate<float(float, float)> TestDelegate; | |
| TestDelegate d; | |
| d.bind<&Func2>(); | |
| d.invoke(10.0f, 20.0f); | |
| Test t; | |
| d.bind<Test, &Test::Func2>(&t); | |
| d.invoke(10.0f, 20.0f); | |
| const Test ct; | |
| d.bind<Test, &Test::Func2>(&ct); | |
| d.invoke(10.0f, 20.0f); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment