Skip to content

Instantly share code, notes, and snippets.

@robmccoll
Last active January 25, 2019 15:09
Show Gist options
  • Save robmccoll/d88bb939c7e90f5bae65c533ba6c200b to your computer and use it in GitHub Desktop.
Save robmccoll/d88bb939c7e90f5bae65c533ba6c200b to your computer and use it in GitHub Desktop.
Attempt at generating Access / Mutate C# style
#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