Skip to content

Instantly share code, notes, and snippets.

@mtao
Last active October 11, 2017 23:15
Show Gist options
  • Save mtao/526a2bdf654bf9de9316324418294c8d to your computer and use it in GitHub Desktop.
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.
#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