Last active
October 1, 2017 04:03
-
-
Save dpzmick/b83f73b74f0ce98f3ac8a6f8dc4acab9 to your computer and use it in GitHub Desktop.
This file contains 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 <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