Last active
October 11, 2017 23:15
-
-
Save mtao/526a2bdf654bf9de9316324418294c8d to your computer and use it in GitHub Desktop.
a tool to enable raii bind/release combos when some classes can have additional data. most annoying challenge was to make it so classes with no extra data didn't have to handle things themselves.
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
| #include <cstddef> | |
| #include <utility> | |
| #include <iostream> | |
| template <typename Obj> | |
| struct bind_enabled { | |
| public: | |
| const Obj& derived() const {return *static_cast<const Obj*>(this);} | |
| Obj& derived() {return *static_cast<Obj*>(this);} | |
| template <typename Optional> | |
| static void bind(int id, const Optional& optional) { | |
| if constexpr(!optional_exists()) { | |
| Obj::bind(id); | |
| } else { | |
| Obj::bind(id,optional); | |
| } | |
| } | |
| void bind() { | |
| bind(id(),optional()); | |
| } | |
| template <typename Optional> | |
| static void release(int id, const Optional& optional) { | |
| if constexpr(!optional_exists()) { | |
| Obj::release(id); | |
| } else { | |
| Obj::release(id,optional); | |
| } | |
| } | |
| void release() { | |
| release(id(),optional()); | |
| } | |
| int id() const { return derived().id(); } | |
| auto optional() const { | |
| if constexpr(optional_exists<Obj>()) { | |
| return derived().optional(); | |
| } else { | |
| return nullptr; | |
| } | |
| } | |
| private: | |
| template <typename U=Obj> constexpr static bool optional_exists() {return optional_exists_<U>(0);} | |
| //&U::optional has a reference in order to make it a ptr type so passing 0 works | |
| template <typename U> constexpr static bool optional_exists_(decltype(&U::optional)) {return true;} | |
| //C style varargs to let anything passed in works | |
| template <typename U> constexpr static bool optional_exists_(...) {return false;} | |
| }; | |
| template <typename Bindable> | |
| struct Binder { | |
| public: | |
| using optional_data_type = decltype(std::declval<Bindable>().optional()); | |
| Binder(const Bindable& obj): m_id(obj.id()), m_optional(obj.optional()) { | |
| Bindable::bind(m_id, m_optional); | |
| } | |
| ~Binder() { | |
| Bindable::release(m_id,m_optional); | |
| } | |
| private: | |
| int m_id; | |
| optional_data_type m_optional; | |
| }; | |
| template <typename Obj> | |
| auto make_binder(const Obj& o) { return Binder<bind_enabled<Obj>>(o); } | |
| class A: public bind_enabled<A> { | |
| public: | |
| int id() const { return m_id; } | |
| auto bind() const { return make_binder(*this); } | |
| static void bind(int id) { | |
| std::cout << "Binding a type a with optional null " << std::endl; | |
| } | |
| static void release(int id) { | |
| std::cout << "Releasing a type a with optional null " << std::endl; | |
| } | |
| private: | |
| int m_id = 0; | |
| }; | |
| class B: public bind_enabled<B> { | |
| public: | |
| struct optional_data { | |
| public: | |
| optional_data(int i): m_i(i) {} | |
| int i() const { return m_i;} | |
| int m_i; | |
| }; | |
| int id() const { return m_id; } | |
| auto optional() const {return optional_data(4);} | |
| static void bind(int id, const optional_data& data) { | |
| std::cout << "Binding a type b with optional: " << data.i() << std::endl; | |
| } | |
| static void release(int id, const optional_data& data) { | |
| std::cout << "Releasing a type b with optional: " << data.i() << std::endl; | |
| } | |
| auto bind() const { return make_binder(*this); } | |
| private: | |
| int m_id = 1; | |
| }; | |
| int main() { | |
| { | |
| A a; | |
| std::cout << "A bind: " << std::endl; | |
| auto as = a.bind(); | |
| } | |
| { | |
| B b; | |
| std::cout << "B bind: " << std::endl; | |
| auto bs = b.bind(); | |
| } | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment