Skip to content

Instantly share code, notes, and snippets.

@dpzmick
Last active October 1, 2017 04:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dpzmick/b83f73b74f0ce98f3ac8a6f8dc4acab9 to your computer and use it in GitHub Desktop.
Save dpzmick/b83f73b74f0ce98f3ac8a6f8dc4acab9 to your computer and use it in GitHub Desktop.
#include <cstddef>
#include <iostream>
#include <type_traits>
struct nil { };
template <typename H, class T>
struct cons
{
using head = H;
using tail = T;
};
template <typename... Args>
struct mklist;
template <>
struct mklist<>
{
using list = nil;
};
template <typename First, typename... Args>
struct mklist<First, Args...>
{
using list = cons<First, typename mklist<Args...>::list>;
};
template <typename Target, typename List>
struct contains;
template <typename H, typename T>
struct contains<H, cons<H, T>>
{
static constexpr bool value = true;
};
template <typename NotH, typename H, typename T>
struct contains<NotH, cons<H, T>>
{
static constexpr bool value = contains<NotH, T>::value;
};
template <typename H>
struct contains<H, nil>
{
static constexpr bool value = false;
};
template <typename T>
struct FieldInfo;
template <typename T, size_t offset_>
struct Field
{
using type = T;
static constexpr size_t offset = offset_;
};
template <typename T>
struct View
{
using info = FieldInfo<T>;
View(T& s) : s_(s) { }
T& ref() { return s_; }
private:
T& s_;
};
template <typename Field, typename View>
typename std::enable_if_t<
contains<Field, typename View::writable>::value,
typename Field::type&>
get(View& v)
{
auto& ref = v.ref();
char* hack = reinterpret_cast<char*>(&ref);
return *reinterpret_cast<typename Field::type*>(hack + Field::offset);
}
template <typename Field, typename View>
typename std::enable_if_t<
contains<Field, typename View::readonly>::value,
const typename Field::type&>
get(View& v)
{
auto& ref = v.ref();
const char* hack = reinterpret_cast<char*>(&ref);
return *reinterpret_cast<const typename Field::type*>(hack + Field::offset);
}
#define GET(s, f, v) get<FieldInfo<s>::f>(v)
// example usage
struct MyStruct
{
int a;
double b;
std::string c;
};
template <>
struct FieldInfo<MyStruct>
{
using a = Field<int, offsetof(MyStruct, a)>;
using b = Field<double, offsetof(MyStruct, b)>;
using c = Field<std::string, offsetof(MyStruct, c)>;
using fields = mklist<a, b, c>::list;
};
struct MyView : public View<MyStruct>
{
MyView(MyStruct& s) : View<MyStruct>(s) { }
using readonly = mklist<info::a>::list;
using writable = mklist<info::b>::list;
};
struct MyView1 : public View<MyStruct>
{
MyView1(MyStruct& s) : View<MyStruct>(s) { }
using readonly = mklist<info::a, info::b>::list;
using writable = mklist<info::c>::list;
};
int main()
{
MyStruct s{12, 1.1, "cats and dogs"};
MyView1 v(s);
//GET(MyStruct, b, v) = 12; // doesn't compile
std::cout << GET(MyStruct, a, v) << std::endl;
std::cout << GET(MyStruct, b, v) << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment