Last active
January 25, 2019 15:09
-
-
Save robmccoll/d88bb939c7e90f5bae65c533ba6c200b to your computer and use it in GitHub Desktop.
Attempt at generating Access / Mutate C# style
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 <iostream> | |
#include <string> | |
#include <exception> | |
// The idea is to provide conveniences that: | |
// - create get() and set() methods for you | |
// - have low boilerplate | |
// - be easy to read / understand (if something is declared rewrite<class> name; | |
// I can expect that it has get() and set() methods). | |
// - allow easy override / implementation later | |
// This is a half-baked implementaiton and could probably be improved | |
// (for example removing the storage). | |
// LIBRARY-ISH SETUP CODE | |
template<class C, typename T> class field { | |
friend C; | |
protected: | |
T data; | |
public: | |
field() {} | |
field(T d) : data(d) {} | |
field<C, T> operator=(T not_allowed) { | |
throw new std::logic_error("Cannot directly assign mutable instance. Use set."); | |
} | |
}; | |
template<class C, typename T> class read : public field<C, T> { | |
private: | |
C *c; | |
T (C::*r)(); | |
public: | |
read() : | |
c(NULL), r(NULL) {} | |
read(C *c, T (C::*r)()) : | |
c(c), r(r) {} | |
read(C *c, T (C::*r)(), T d) : | |
c(c), r(r), field<C, T>(d) {} | |
read(T d) : | |
c(NULL), r(NULL), field<C, T>(d) {} | |
T get() { return c && r ? (c->*r)() : this->data; } | |
}; | |
template<class C, typename T> class write : public field<C, T> { | |
private: | |
C *c; | |
T (C::*w)(T); | |
public: | |
write() : | |
c(NULL), w(NULL) {} | |
write(C *c, T (C::*w)(T)) : | |
c(c), w(w) {} | |
write(C *c, T (C::*w)(T), T d) : | |
c(c), w(w), field<C, T>(d) {} | |
write(T d) : | |
c(NULL), w(NULL), field<C, T>(d) {} | |
T set(T data) { return (c && w) ? (c->*w)(data) : this->data = data; } | |
}; | |
template<class C, typename T> class rewrite : public field<C, T> { | |
private: | |
C *c; | |
T (C::*r)(); | |
T (C::*w)(T); | |
public: | |
rewrite() : | |
c(NULL), r(NULL), w(NULL) {} | |
rewrite(C *c, T (C::*r)()) : | |
c(c), r(r), w(NULL) {} | |
rewrite(C *c, T (C::*r)(), T d) : | |
c(c), r(r), w(NULL), field<C, T>(d) {} | |
rewrite(C *c, T (C::*w)(T)) : | |
c(c), r(NULL), w(w) {} | |
rewrite(C *c, T (C::*w)(T), T d) : | |
c(c), r(NULL), w(w), field<C, T>(d) {} | |
rewrite(C *c, T (C::*r)(), T (C::*w)(T)) : | |
c(c), r(r), w(w) {} | |
rewrite(C *c, T (C::*r)(), T(C::*w)(T), T d) : | |
c(c), r(r), w(w), field<C, T>(d) {} | |
rewrite(T d) : | |
c(NULL), r(NULL), w(NULL), field<C, T>(d) {} | |
T get() { return c && r ? (c->*r)() : this->data; } | |
T set(T data) { return (c && w) ? (c->*w)(data) : this->data = data; } | |
}; | |
// USAGE EXAMPLE | |
class exp { | |
public: | |
exp() : | |
ro(this, &exp::get_ro, "def"), | |
name("og") | |
{} | |
rewrite<exp, std::string> name; | |
write <exp, std::string> other_name; | |
read <exp, std::string> ro; | |
void change_ro() { | |
ro.data ="new val"; | |
} | |
std::string combined() { | |
return name.data + " " + other_name.data; | |
} | |
std::string get_ro() { | |
return ro.data + " " + name.data + " " + other_name.data; | |
} | |
}; | |
int | |
main(int argc, char *argv[]) | |
{ | |
exp e; | |
std::cout << e.name.get() << std::endl; | |
e.name.set("test"); | |
std::cout << e.name.get() << std::endl; | |
e.other_name.set("test"); | |
std::cout << e.combined() << std::endl; | |
std::cout << e.ro.get() << std::endl; | |
e.change_ro(); | |
std::cout << e.ro.get() << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment