Last active
August 29, 2015 14:01
-
-
Save markpapadakis/42aa05883652d524cd3f to your computer and use it in GitHub Desktop.
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
| // A simple std::function alternative. | |
| // You can use e.g variadic templates to support arbitrary signatures, but this here demonstrates how | |
| // type erasure makes it possible to wrap any callable function | |
| // | |
| // type erasure is a nifty C++ pattern. There are alternatives to it, but this is usually a better fit. | |
| // | |
| // move/copy constructors and assignemnt operators not implemented, but trivial to do so anyway | |
| // May be worth using e.g std::unique_ptr or whatever for ref-counted wrapped object for sharing, but should | |
| // also be trivial to implement. Apparenly you need a few different alternative implementations to satisfy different | |
| // requirements; can't practically have one impl. for everything. | |
| struct function | |
| { | |
| struct interface | |
| { | |
| virtual ~interface(void) | |
| { | |
| } | |
| virtual void invoke(void) = 0; | |
| }; | |
| template<typename T> | |
| struct impl | |
| : interface | |
| { | |
| T value; | |
| impl(const T &v) | |
| : value(v) | |
| { | |
| } | |
| void invoke(void) override | |
| { | |
| value(); | |
| } | |
| void *operator new(size_t, void *ptr) | |
| { | |
| return ptr; | |
| } | |
| void *operator new(const size_t size) | |
| { | |
| return malloc(size); | |
| } | |
| }; | |
| interface *const binding; // just so because this can be == nullptr, otherwise we 'd use a union | |
| uint8_t _b[128]; | |
| function(void) | |
| : binding(nullptr) | |
| { | |
| } | |
| template<typename T> | |
| function(const T &v) | |
| : binding(sizeof(impl<T>) <= sizeof(_b) | |
| ? new (_b)impl<T>(v) | |
| : new impl<T>(v)) | |
| { | |
| } | |
| ~function(void) | |
| { | |
| if (binding != (decltype(binding))_b) | |
| delete binding; | |
| else | |
| binding->~interface(); | |
| } | |
| void operator()(void) | |
| { | |
| if (binding != nullptr) | |
| binding->invoke(); | |
| } | |
| }; | |
| struct Callable | |
| { | |
| inline void operator()(void) | |
| { | |
| puts("Hello"); | |
| } | |
| }; | |
| static void PrintHello(void) | |
| { | |
| puts("Hello"); | |
| } | |
| int main(void) | |
| { | |
| //Either of those 3 will work | |
| //function f([](void) { puts("Hello"); }); | |
| //function f((void(*)(void))PrintHello); | |
| //Callable c; function f(c); | |
| f(); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment