Skip to content

Instantly share code, notes, and snippets.

@albeva
Last active August 29, 2015 13:57
Show Gist options
  • Save albeva/9551571 to your computer and use it in GitHub Desktop.
Save albeva/9551571 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <type_traits>
/**
* Property template encapsulates the callback
* functions to getter and setter of the property.
* it does not store the propertyu value itself
*/
template<typename T, class U, T(U::*getter_fn)(), void(U::*setter_fn)(T&&)>
class Property
{
public:
/**
* create property object from a pointer to the object,
* getter and setter proxy functions
*/
Property(U * obj) : _obj(obj) {}
/**
* Allow assigning value to the property via '=' operator
* this should do perfect forwarding
*/
template<typename V>
inline void operator = (V && value)
{
(_obj->*setter_fn)(std::forward<V>(value));
}
/**
* Overoad the operator for T so that propety can be simply
* assigned.
* int p = obj.int_prop;
*/
inline operator T() const {
return (_obj->*getter_fn)();
}
/**
* Override the () operators so that propert getter
* can be called like a functor
*/
inline T operator()() const {
return (_obj->*getter_fn)();
}
private:
U * _obj;
};
/**
* Allow property to be used easily with output streams
* std::cout << obj.prop;
*/
template<typename T, class U, T(U::*getter_fn)(), void(U::*setter_fn)(T&&)>
std::ostream& operator<<(std::ostream& os, const Property<T, U, getter_fn, setter_fn> & prop)
{
os << prop();
return os;
}
/**
* helper macro for creating the propert.
* usage:
* propert(int, age, { return _age; }, { _age = value; }
*/
#define property(T, _name, _class, _getter, _setter) \
public: \
T _##_name; \
T get_##_name() _getter; \
void set_##_name(T && value) _setter; \
public: \
Property<T, _class, &_class::get_##_name, &_class::set_##_name> _name = this;
/**
* test properties
*/
class Person
{
// age
property(int, age, Person, {
return _age;
}, {
_age = value;
});
// name
property(std::string, name, Person, {
return _name;
}, {
_name = value;
});
// greeting
property(std::string, greeting, Person, {
return "Hello. My name is " + _name + " and I am " + std::to_string(_age) + " years old.";
}, {});
};
int main(int argc, char * argv[])
{
Person me;
me.age = 28;
me.name = "Albert";
std::cout << me.greeting << '\n';
std::cout << "sizeof(Person) = " << sizeof(Person) << '\n';
return 0;
}
@sohailsomani
Copy link

This is pretty clever! The key bit that makes it work is inline initialization for member variables. You should probably mark this as C++11 only

@LordTocs
Copy link

Careful with prefixing '_'. There are some rules.

So if I use property(int, Age, ..., ...); I get potential issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment