Monday, July 21, 2008

c++: property

Recently I'd touched an article about properties in python. They were implemented using special function property and looked very elegant:

class A(object):
  def __init__(self):
    self._x = None

  def get_x(self):
    return self._x

  def set_x(self, x):
    self._x = x

  x = property(get_x, set_x)

obj = A()
obj.x = 6    # set
print obj.x  # get
We don't have such option in c++. But it's quite simple to create one. Some implementation I saw were ugly indeed. They used a lot of code and wanted to call some routines in constructor. My version of property in c++:
#include <iostream>

template<typename T, 
         T(*s)(T &, const T &), 
         T(*g)(T &)>
class property
{
    public:
        
        T operator =(const T &nt)
        {
            return s(t, nt);
        }

        operator T()
        {
            return g(t);
        }

    protected:

        T t;
};

class A
{
    public:

        static int setter(int &i, const int &ni)
        {
            cout << "S" << endl;
            i = ni;

            return i;
        }

        static int getter(int &i)
        {
            cout << "G" << endl;

            return i;
        }

        property<int, setter, getter> p;
};

int main(int argc, char **argv)
{
    A a;

    a.p = 6;
    std::cout << a.p;

    return 0;
}
You have to define 2 static class methods(or just functions, doesn't matter) for setter and getter of the property. The modified version of class property may have default setter and getter:
template<typename T>
T setter(T &i, const T &ni)
{
    i = ni;

    return i;
}

template<typename T>
T getter(T &i)
{
    return i;
}

template<typename T, 
         T(*s)(T &, const T &) = setter<T>, 
         T(*g)(T &) = getter<T> >
class property
{
    public:
        
        T operator =(const T &nt)
        {
            return s(t, nt);
        }

        operator T()
        {
            return g(t);
        }

    protected:

        T t;
};
Now you can customize only one of them:
int getter(int &i)
{
    cout << "G" << endl;

    return i;
}

class A
{
    public:

        A(int a)
        {
            p = a;
        }


        property<int, setter<int>, getter> p;
};