Boost logo

Boost :

From: Alexander Nasonov (alnsn-mycop_at_[hidden])
Date: 2003-07-09 06:52:54


David Abrahams wrote:

> Alexander Nasonov <alnsn-mycop_at_[hidden]> writes:
>
>> Well, sometimes it's needed at compile-time. Though, I don't know how
>> useful it is. Can you give an example?
>
> Heh, you caught me!
>
> Well, if the (member) (function) pointers are available at compile
> time they can be inlined away so that using them becomes more
> efficient.
>
> Suppose I want to write serialization code? Can you
> serialize/deserialize with a runtime-only framework?

Take a look at my example
http://groups.yahoo.com/group/boost/files/describe_classes.tar.gz

and its output (formatting added afterwards)

<object type="Driver">
  <base type="Person">
    <member name="gender" type="char">M</member>
    <member name="birth_date" type="Date">
      <member name="year" type="int">1975</member>
      <member name="month" type="int">12</member>
      <member name="day" type="int">8</member>
    </member>
    <member name="first_name" type="string">Alexander</member>
    <member name="last_name" type="string">Nasonov</member>
  </base>
  <member name="licence_id" type="string">N/A</member>
  <member name="licence_issue_date" type="Date">
    <member name="year" type="int">0</member>
    <member name="month" type="int">0</member>
    <member name="day" type="int">0</member>
  </member>
</object>

You can see that bases and compound types (like Date) are serialized
properly. There is neither pointer nor container support yet. I have some
ideas, though.
Sone words about how it works. First of all, an address of an object and a
type_info are taken. The framework always operates with void* pointer and
type_info. Several types (*_nodes) have virtual functions which casts raw
pointers back to original type and do some action. For example,

class base_node // represent a base of a concrete class
{
    // ...

    //
    virtual void* derived_to_base(void* base_ptr) const = 0;
};

class member_node // represent a member of a concrete class
{
    // ...

    // Apply ->* operator to an object pointed to
    // by raw_ptr and return an address of the result.
    virtual void* dereference(void* raw_ptr) const = 0;
};

The framework uses these functions to access bases or members one by one
until it find elemetary types like int, char or std::string. When such type
is found you can print it or assign a new value to it.

For example, you have a raw pointer to Driver and you want to get a member
represended by some member_node node. Let's say node holds a pointer to
Driver::licence_issue_date. You can call node.dereference(raw_driver) to
get a raw address of this member and node.member_type() to get its type.
Then, if member type (Date in this case) isn't an elemenary, repeat the
procedure recursively. Otherwise, find a function that can print the
member.

>> Some other questions. How to map member pointers to names?
>
> Add a char const* const parameter? Have an additional parallel array
> of names?
>
>> How to find a member?
>
> By name? By reverse-indexing whatever structure answers the previous
> question, of course!

At compile time?! I can think of this code but I don't like it so much:

template<class Members, const char* Name>
struct find_member;

template <>
struct class_<Driver> // Taken from your post
{
    typedef mpl::vector<Person> bases;

    static const char licence_id[];
    static const char licence_issue_date[];
    static const char accelerate[];

    typedef mpl::vector<
        member<int Driver::*, &Driver::licence_id, licence_id>
      , member<Date Driver::*, &Driver::licence_issue_date,
licence_issue_date>
      , member<void (Driver::*)(), &Driver::accelerate, accelerate>
> members;

          ...
};

typedef find_member<
        class_<Driver>::members,
        class_<Driver>::licence_id
>::type result;

-- 
Alexander Nasonov
Remove minus and all between minus and at from my e-mail for timely response

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