Boost logo

Boost :

Subject: [boost] the best possible c++ properties (implementation).
From: Germán Diago (germandiago_at_[hidden])
Date: 2010-03-01 11:58:22


Hello. I've been trying hard to implement the best possible properties
sytem in c++ (version 0x).

For now, I'm quite satisfied with the result, but it can be improved a little.

The properties are implemented in a header called (surprisingly!) Property.hpp

Classes:

template TROProperty and TRWProperty for trivial properties, which are
those which you can use very straightforward without defining setters
or
getters and it stores the property value inside.

templates RWProperty and ROProperty, for which you need to define a
storage (if needed) and getters and setters.

FEATURES:

- You can define a getter as a function that returns *ANYTHING* and it
will deduce parameters, constness and everything it needs.
- You can define a setter as a function that returns void and takes
one parameter. The deduction machinery will do the rest.

So, for trivial properties there is little to explain:

class Person {
public:
    TROProperty<unsigned int> Age;
    Person(int age) : Age(age) {}
};

int main(int argc, char * argv[])
{
   Person p(26);
   cout << p.Age << endl;
}

For elaborated properties, you have freedom in defining the get and
set functions, as long as the get function gets just one parameter and
the set
function sets one parameter and returns void. The usage of elaborated
properties is done through a macro:

class Agenda {
   typedef Agenda ClassName; //Needed for elaborated properties.

    vector<Person> persons_;

    Person * getCurrentPerson() { return persons_[Position]; }
public:
    TrivialProperty<int> Position;
    PROP_ROPROPERTY(CurrentPerson);
    ....
    Agenda() : PROP_PROPERTY_INIT(CurrentPerson) {};
};

And now it's ready to be used.

For now the features are:

-Implicit conversion to the underlying type.
-Operator overloading (just a sample of the possible operators, just
implemented operator++ and some others)
-Comparison operators...
-Construction assignment, etc from any other property that has a
convertible type or from a data type that makes sense.
- Move and copy construction where it makes sense.
- Compare, for example, a Property<int> to an int or another property
with a convertible value to a Property<int>. If it makes
sense, it must work. The same for any other operator.

- You can obtain the underlying type for a property through
operator(), which makes sense in some contexts. For example, suppose
you have a class Person with properties Name, SurName and Age and a
class Agenda with a property CurrentPerson which returns
a pointer to a Person.

You can do like this:

    string name = agenda.CurrentPerson().Name;

you can assign Name to a string or any other property that accepts a
string (untested but you could).

But you don't need operator() when implicit conversion takes place.

personsbyage_[aperson.Age] //No need for operator(), implicit conversion

Caveats:
   ROProperty
   TROProperty

   I cannot enforce a private operator= because for that I need a
workaround I don't know of or extended friend declarations, which are
part of c++0x.
   So for now, these properties are exactly the same as their
writeable counterparts without read-only enforcement.

In the implementation part, for elaborated properties I have a
template like this:

template <class Getter, class Setter>
class RWProperty;

The same goes for ROProperty. Just with that and the macro to ease the
writing of properties, you can get a property.
These properties must be constructed with the this pointer AND the
pointer to member functions.

I'm experimenting (but I can't find a way to do it) with something like this:

template <class Getter, class Setter, Getter, Setter>
class RWProperty;

so that the construction of properties wouldn't need the pointers,
because they would be passed as template parameters.
But inside the template I have an ambiguity problem. Getter and Setter
are pointer to member function types and Getter and
Setter parameters are the addresses.

For now I've found the properties very usable. The only caveats are
the enforcement of operator= and the passing of
pointer to members as part of initialization. If I can solve those, we
can get a good properties implementation of properties
and the initialization of elaborated properties would be just with the
this pointer (and a value if you want to initialize with a value).

This is a work in progress. For now I've used c++0x, but I think I can
use BOOST_TYPEOF (maybe) and some other things in order
to translate it to current c++.

The code is attached. It's an (unfinished) miniapplication of an
Agenda made in gtkmm compiled under g++ 4.5 svn. Take a look at the
Property.hpp and the application and tell me what you think. I would
like to be able to pass pointer to member functions as template
arguments in order to avoid initialization of pointers as parameters.

compile with:

g++ -std=c++0x `pkg-config gtkmm-2.4 --libs --cflags` Person.cpp
Agenda.cpp Window.cpp main.cpp -o Agenda

You can just add people with "Añadir" Button and traverse with < and >
button. It does not do anything special, it's just to test properties.




Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk