Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

for each member of a sturcture/class ?

221 views
Skip to first unread message

Jim Langston

unread,
Dec 17, 2007, 11:19:22 AM12/17/07
to
One thing that would help me a lot in code would be something that allowed
me to iterate through the members of a class or structure. Consider
serialization.

To serialize a class or structure I need to serialze each type (not hard)
then in the class serialize each variable. For a simple structure, such as
holding integers and std::strings, if there was some way to iterate through
the variables it would be simple something like in pseudo code:

std::ostream& operator<<( std::ostream& os)
{
for_each_member( os << member );
}

There is also a case where I want to tie a structure/class into a database
and need to go through each variable and call a function to tie it in, a
simple thing if there was a way to call something for each variable.

I can't even think how to try to do this in C++ currently.

--
Jim Langston
tazm...@rocketmail.com

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

hhs...@gmail.com

unread,
Dec 17, 2007, 11:58:43 AM12/17/07
to
On 17 Dec, 13:19, tazmas...@rocketmail.com ("Jim Langston") wrote:
> One thing that would help me a lot in code would be something that allowed
> me to iterate through the members of a class or structure. Consider
> serialization.

What you need is something like reflection, which is not possible in C+
+.

>
> To serialize a class or structure I need to serialze each type (not hard)
> then in the class serialize each variable. For a simple structure, such as
> holding integers and std::strings, if there was some way to iterate through
> the variables it would be simple something like in pseudo code:
>
> std::ostream& operator<<( std::ostream& os)
> {
> for_each_member( os << member );
>
> }
>
> There is also a case where I want to tie a structure/class into a database
> and need to go through each variable and call a function to tie it in, a
> simple thing if there was a way to call something for each variable.
>
> I can't even think how to try to do this in C++ currently.
>

Overloading the << operator seems to be the best way. Although it
requires some maintenance in the class itself, it hides the actual
implementation from the clients of the class.

Best,
Hernan

Larry Evans

unread,
Dec 17, 2007, 1:38:08 PM12/17/07
to
On 12/17/07 10:19, Jim Langston wrote:
[snip]

> To serialize a class or structure I need to serialze each type (not hard)
> then in the class serialize each variable.
[snip]

> There is also a case where I want to tie a structure/class into a database
> and need to go through each variable and call a function to tie it in, a
> simple thing if there was a way to call something for each variable.
Boost has a serialization library from which you might get some ideas:

http://www.boost.org/libs/serialization/doc/index.html

There was also some posts about database interfaces here:

http://archives.free.net.ph/message/20061205.092349.9e2ebf91.en.html

HTH
-Larry

Mathias Gaunard

unread,
Dec 18, 2007, 2:19:08 AM12/18/07
to
On 17 déc, 17:19, tazmas...@rocketmail.com ("Jim Langston") wrote:

> std::ostream& operator<<( std::ostream& os)
> {
> for_each_member( os << member );
>
> }

> [...]


>
> I can't even think how to try to do this in C++ currently.

Make a type list of function object types with all your members and
simply iterate it.

Roman.Pe...@gmail.com

unread,
Dec 18, 2007, 9:51:48 AM12/18/07
to
On 17 Dec, 19:19, tazmas...@rocketmail.com ("Jim Langston") wrote:
> One thing that would help me a lot in code would be something that allowed
> me to iterate through the members of a class or structure. Consider
> serialization.
>
> To serialize a class or structure I need to serialze each type (not hard)
> then in the class serialize each variable. For a simple structure, such as
> holding integers and std::strings, if there was some way to iterate through
> the variables it would be simple something like in pseudo code:
>
> std::ostream& operator<<( std::ostream& os)
> {
> for_each_member( os << member );
>
> }
>
> There is also a case where I want to tie a structure/class into a database
> and need to go through each variable and call a function to tie it in, a
> simple thing if there was a way to call something for each variable.
>
> I can't even think how to try to do this in C++ currently.
>
> --
> Jim Langston
> tazmas...@rocketmail.com

Take a look at boost::fusion. There are algorithms for iteration,
transformation and so on, which you can use against fields
of your structure after adapting it with
BOOST_FUSION_ADAPT_STRUCT macros.

#include <iostream>
#include <string>

#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>

using namespace std;
using namespace boost;

// structure, which fields you'd like to iterate
struct asset
{
string name;
double price;
};

// it makes asset a fusion sequence
// you can use fusion algorithms against asset
BOOST_FUSION_ADAPT_STRUCT(asset,
(string, name)
(double, price)
)

struct print
{
print(ostream & strm) : m_strm(strm) {}

template <class T>
void operator()(const T & val) const
{
m_strm << val << endl;
}

private:
ostream & m_strm;
};

ostream & operator<<(ostream & strm, const asset & as)
{
// iterate over all fields of asset and print each of them
fusion::for_each(as, print(strm));
return strm;
}

int main(int argc, char * argv[])
{
asset as = { "book", 49.99 };
cout << as << endl;
}

Regards,
Roman Perepelitsa.

Roman.Pe...@gmail.com

unread,
Dec 18, 2007, 11:58:02 AM12/18/07
to
On 17 Dec, 19:19, tazmas...@rocketmail.com ("Jim Langston") wrote:
> One thing that would help me a lot in code would be something that allowed
> me to iterate through the members of a class or structure. Consider
> serialization.
>
> To serialize a class or structure I need to serialze each type (not hard)
> then in the class serialize each variable. For a simple structure, such as
> holding integers and std::strings, if there was some way to iterate through
> the variables it would be simple something like in pseudo code:
>
> std::ostream& operator<<( std::ostream& os)
> {
> for_each_member( os << member );
>
> }
>
> There is also a case where I want to tie a structure/class into a database
> and need to go through each variable and call a function to tie it in, a
> simple thing if there was a way to call something for each variable.
>
> I can't even think how to try to do this in C++ currently.
>
> --
> Jim Langston
> tazmas...@rocketmail.com

#include <iostream>
#include <string>

#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>

private:
ostream & m_strm;
};

Regards,
Roman Perepelitsa.

---

Jim Langston

unread,
Dec 18, 2007, 1:07:45 PM12/18/07
to
"Jim Langston" wrote:
> One thing that would help me a lot in code would be something that
> allowed me to iterate through the members of a class or structure.
> Consider serialization.
>
> To serialize a class or structure I need to serialze each type (not
> hard) then in the class serialize each variable. For a simple
> structure, such as holding integers and std::strings, if there was
> some way to iterate through the variables it would be simple
> something like in pseudo code:
> std::ostream& operator<<( std::ostream& os)
> {
> for_each_member( os << member );
> }
>
> There is also a case where I want to tie a structure/class into a
> database and need to go through each variable and call a function to
> tie it in, a simple thing if there was a way to call something for
> each variable.
> I can't even think how to try to do this in C++ currently.

Looking at both boost::fustion and boost serialization they are doing the
exact thing I don't want to do, list each member of the structure twice.
Once in the class declaration, once in some other function/method. That I
can already do in my code which is what I'm trying to prevent.

C++ does nto currently have a way to do it, it's not part of the language.

Martijn Meijering

unread,
Dec 18, 2007, 2:30:16 PM12/18/07
to
Jim Langston wrote:
> Looking at both boost::fustion and boost serialization they are doing the
> exact thing I don't want to do, list each member of the structure twice.
> Once in the class declaration, once in some other function/method. That I
> can already do in my code which is what I'm trying to prevent.

I'm not familiar with boost::fusion, but I agree with your goal to
eliminate duplication. Once And Only Once, Don't Repeat Yourself. It's a
pity boost::fusion apparently doesn't allow you to do that.

> C++ does nto currently have a way to do it, it's not part of the language.

If you /really/ want to do it, you can do it with preprocessor
meta-programming, at the cost of using macro's to declare member variables.

With a lot of work (and a lot of peeking at the boost preprocessor
library) I was able to write a macro DECLARE_FIELDS that allows you to
write this:

class Pipo
{
public:
DECLARE_FIELDS
(
((int,a))
((string,b))
)
};

and get enough meta-information to allow you to implement a ForEach
member function template that you can use as follows:

class Op
{
public:
template<class T>
void operator()(const T& t) const
{
// cout << t << endl;
}
};

void TestForEach()
{
Pipo pipo;
Op op;
pipo.ForEach(op);
}

I'm not really sure this is conforming code, in particular whether the
argument list to DECLARE_FIELDS is allowed to span multiple lines. FWIW,
it does compile with Visual Studio 6.0.

Writing such code is an interesting challenge, but it feels really wrong
that we should need to do something so complicated as this to something
as essential as eliminating redundancy.

Ideally it should be possible to do this within the language itself. If
we have to resort to using the preprocessor it would help a lot if we
actually had a decent preprocessor, instead of the brain-dead
preprocessor we have today.

I would rather see it done in the language itself, but realistically,
it's going to be long time before C++ has evolved enough to make most of
the subtle trickery in boost unnecessary. In the meantime it would help
a lot if we had a decent preprocessor. It seems to me that it wouldn't
be too difficult to add functionality to the preprocessor that
eliminates most of the trickery in the boost preprocessor
metaprogramming library. I'm thinking of if's and for's, overloading and
recursion. We are already getting variadic macro's.

But perhaps things are more subtle than I think. I wonder what the
experts think about this.

Roman.Pe...@gmail.com

unread,
Dec 19, 2007, 12:09:24 PM12/19/07
to
On 18 Dec, 21:07, "Jim Langston" <tazmas...@rocketmail.com> wrote:
> Looking at both boost::fustion and boost serialization they are doing the
> exact thing I don't want to do, list each member of the structure twice.
> Once in the class declaration, once in some other function/method. That I
> can already do in my code which is what I'm trying to prevent.
>
> C++ does nto currently have a way to do it, it's not part of the language.

As Martijn Meijering mentioned, you can do it using preprocessor. Note
the use of DECLARE_STRUCT macro, which shows how you can declare
struct without specifying each field twice.

#include <iostream>
#include <string>

#include <boost/preprocessor.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>

#define DEFINE_STRUCT(name, fields) \
DEFINE_STRUCT_I(name, \
BOOST_PP_CAT(DEFINE_STRUCT_X fields, 0))

#define DEFINE_STRUCT_X(x, y) ((x, y)) DEFINE_STRUCT_Y
#define DEFINE_STRUCT_Y(x, y) ((x, y)) DEFINE_STRUCT_X
#define DEFINE_STRUCT_X0
#define DEFINE_STRUCT_Y0

#define DEFINE_STRUCT_I(name, fields) \
struct name \
{ \
BOOST_PP_SEQ_FOR_EACH_I \
(DEFINE_STRUCT_FIELD, _, fields) \
}; \
BOOST_FUSION_ADAPT_STRUCT_I(name, fields)

#define DEFINE_STRUCT_FIELD(r, _, i, xy) \
BOOST_PP_TUPLE_ELEM(2, 0, xy) \
BOOST_PP_TUPLE_ELEM(2, 1, xy);

using namespace std;
using namespace boost;

DEFINE_STRUCT(asset,


(string, name)
(double, price)
)

struct print
{
print(ostream & strm) : m_strm(strm) {}

template <class T>


void operator()(const T & val) const
{
m_strm << val << endl;
}

private:
ostream & m_strm;
};

ostream & operator<<(ostream & strm, const asset & as)
{

fusion::for_each(as, print(strm));
return strm;
}

int main(int argc, char * argv[])
{
asset as = { "book", 49.99 };
cout << as << endl;
}

Regards,
Roman Perepelitsa.

---

Martijn Meijering

unread,
Dec 19, 2007, 12:32:18 PM12/19/07
to
Roman.Pe...@gmail.com wrote:
> As Martijn Meijering mentioned, you can do it using preprocessor. Note
> the use of DECLARE_STRUCT macro, which shows how you can declare
> struct without specifying each field twice.

[snip]

> DEFINE_STRUCT(asset,
> (string, name)
> (double, price)
> )

Nice.

Is there a comma missing after (string, name) or does it work as is?
Your example suggests that you are in fact allowed to have macro
arguments span multiple lines, something I wasn't sure of. Can anyone
confirm this is the case?

And is this something you would use in production code? I imagine it
confuses things like Intellisense, which would be a pity.

It seems to me that we aren't very far removed from what needs to be
done to do this sort of thing without boost. If type lists were added to
typeinfo, wouldn't that do the trick?

Roman.Pe...@gmail.com

unread,
Dec 20, 2007, 12:28:36 PM12/20/07
to
On 19 Dec, 20:32, x...@y.z (Martijn Meijering) wrote:
> > DEFINE_STRUCT(asset,
> > (string, name)
> > (double, price)
> > )
>
> Nice.
>
> Is there a comma missing after (string, name) or does it work as is?
> Your example suggests that you are in fact allowed to have macro
> arguments span multiple lines, something I wasn't sure of. Can anyone
> confirm this is the case?

Yes, it works as is; there is no need for additional commas. And yes,
macro arguments can span multiple lines.

> And is this something you would use in production code? I imagine it
> confuses things like Intellisense, which would be a pity.

Yes, sometimes I resort to use preprocessor metaprogramming.
It's ugly, Intellisense unfriendly, but it could be better than other
solutions in some cases.

By the way, boost itself heavily uses preprocessor
metaprogramming. In C++0X most of it will go away, but at the
moment you either have to copy-pase large chunks of code,
use preprocessor or generate code with the help of external tool.

> It seems to me that we aren't very far removed from what needs to be
> done to do this sort of thing without boost.

Without boost it's way harder. Note that fusion::for_each is not the
only
algorithm you can use with 'asset' structure. There are plenty of
useful
algorithms in fusion and 'asset' is compatible with them.

> If type lists were added to typeinfo, wouldn't that do the trick?

Lists added to typeinfo? What do you mean?

Regards,
Roman Perepelitsa.

Martijn Meijering

unread,
Dec 20, 2007, 4:44:00 PM12/20/07
to
Roman.Pe...@gmail.com wrote:
> Yes, it works as is; there is no need for additional commas. And yes,
> macro arguments can span multiple lines.

Cool, thanks!

> Yes, sometimes I resort to use preprocessor metaprogramming.
> It's ugly, Intellisense unfriendly, but it could be better than other
> solutions in some cases.

Agreed.

> By the way, boost itself heavily uses preprocessor
> metaprogramming. In C++0X most of it will go away, but at the
> moment you either have to copy-pase large chunks of code,
> use preprocessor or generate code with the help of external tool.
>
>
>>It seems to me that we aren't very far removed from what needs to be
>>done to do this sort of thing without boost.
>
>
> Without boost it's way harder. Note that fusion::for_each is not the
> only
> algorithm you can use with 'asset' structure. There are plenty of
> useful
> algorithms in fusion and 'asset' is compatible with them.

Sounds like something I need to study more closely!

>>If type lists were added to typeinfo, wouldn't that do the trick?
>
>
> Lists added to typeinfo? What do you mean?

Oops, it seems I meant type_info, I guess it shows that I don't use it
very often :-)

I meant that type_info seems like the right place to store detailed
information about types. If I'm not mistaken, about all it does now is
generate an implementation-defined string representation and allow
instances of type_info to be compared for equality.

For persistance, serialisation etc you'd want to be able to loop over
all members and for each member be able to fetch a pointer to member.
With that pointer you could retrieve a value from an instance of the
type and write it to a stream or something. This isn't really a
typelist, but more a list of pairs of strings and function pointers.

I don't think you can fit this information into a fixed data structure
such as the type type_info. What you could do is have the compiler
generate a new subclass of type_info for every type whose typeinfo you
retrieve with typeid.

I was thinking that if we give type_info a virtual member ForEach, we
could use it to loop over the elements of the type and do something
appropriate. Now that I think more closely about it, I think that would
require a combination of member templates and virtual functions, which
is not possible at present and unlikely to be in future. Maybe you could
do something with decltype. Or maybe it is harder than I think.

I guess I'm just wondering how difficult it would be to add proper
reflection to C++. It would be nice if you could pass a templatised
closure to type_info.ForEach... How far do you think we are away from this?

restor

unread,
Dec 20, 2007, 4:45:05 PM12/20/07
to
Hi all,
I am not very good at C++ metaprogramming, so what I say may be wrong,
but it seams that C++0x is getting close to compile-time "reflection".
Type traits library already requires impemntations to provide
information such as has_nothrow_copy_constructor. Would it not be
relatively easy to implement yet another trait: tuple_representation,
which would expose a tuple interface to any struct/class? Tuples can
be iterated over at compile time, so defining common operations for
all members would be fairly easy.
Of course access specifiers would have to be respected, so there would
have to be a trickery like:

class CC{
public: int i;
private: double x;
};

CC c = { 1, 0.5 };

std::tuple_representation<CC> & ccTuple =
std::tuple_representation(cc);
ccTuple.get<0>(); // ok, return 1
ccTuple.get<1>(); // error: function
"std::tuple_representation::get<1>()" is private.

Would it be feasible?
Andrzej Krzemienski

german diago

unread,
Dec 22, 2007, 10:12:02 AM12/22/07
to
On 17 dic, 17:19, tazmas...@rocketmail.com ("Jim Langston") wrote:
> One thing that would help me a lot in code would be something that allowed
> me to iterate through the members of a class or structure. Consider
> serialization.
>
> To serialize a class or structure I need to serialze each type (not hard)
> then in the class serialize each variable. For a simple structure, such as
> holding integers and std::strings, if there was some way to iterate through
> the variables it would be simple something like in pseudo code:
>
> std::ostream& operator<<( std::ostream& os)
> {
> for_each_member( os << member );
>
> }
>
> There is also a case where I want to tie a structure/class into a database
> and need to go through each variable and call a function to tie it in, a
> simple thing if there was a way to call something for each variable.
>
> I can't even think how to try to do this in C++ currently.
>
> --
> Jim Langston
> tazmas...@rocketmail.com

>
> ---
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]
> [ your news-reader. If that fails, use mailto:std-...@ncar.ucar.edu ]

> [ --- Please see the FAQ before posting. --- ]
> [ FAQ:http://www.comeaucomputing.com/csc/faq.html ]

I was working in a library for serialization, and I tried my best to
write the minimal amount of code
to serialize an object. The library is not finished yet, but what I
have now is something like this:

/This type is similar to a tuple, but holds pointers
template <class... Args>
class DataSerializer {...};


class MyClass
{
public:
typedef DataSerializer<int, float> serialization_data;

private:
int a;
float c;

public:
SerialData data(){ return serialization_data(a, c); }
};

Now we have a save() and restore() function for obects. It's a
function template that saves or restores data.
As long as a type has a specialization of Serializable concept, the
type can be serialized. Built-in types are
serializable by default.
And if you have, for example, MyClass inside another class and MyClass
is serializable because you wrote
its requirements to meet the conept,:

class AnotherClass
{
int a;
string b;

//MyClass meets serializable concept
MyClass m;

typedef SerialData<int, string, MyClass> serial_data;

serial_data data() { return serial_data(a, b, m); }
};

Now you have, for example:

AnotherClass c;
save(c, myfile);

save is a generic algorithm that can serialize serializable types, as
long as they meet requirements.
So with minimal code, you can serialize data. Next things are pointers
and stl containers.

Roman.Pe...@gmail.com

unread,
Dec 24, 2007, 9:11:16 PM12/24/07
to
On 21 Dec, 00:44, x...@y.z (Martijn Meijering) wrote:
> I meant that type_info seems like the right place to store detailed
> information about types. If I'm not mistaken, about all it does now is
> generate an implementation-defined string representation and allow
> instances of type_info to be compared for equality.
>
> For persistance, serialisation etc you'd want to be able to loop over
> all members and for each member be able to fetch a pointer to member.
> With that pointer you could retrieve a value from an instance of the
> type and write it to a stream or something. This isn't really a
> typelist, but more a list of pairs of strings and function pointers.
>
> I don't think you can fit this information into a fixed data structure
> such as the type type_info. What you could do is have the compiler
> generate a new subclass of type_info for every type whose typeinfo you
> retrieve with typeid.
>
> I was thinking that if we give type_info a virtual member ForEach, we
> could use it to loop over the elements of the type and do something
> appropriate. Now that I think more closely about it, I think that would
> require a combination of member templates and virtual functions, which
> is not possible at present and unlikely to be in future. Maybe you could
> do something with decltype. Or maybe it is harder than I think.
>
> I guess I'm just wondering how difficult it would be to add proper
> reflection to C++. It would be nice if you could pass a templatised
> closure to type_info.ForEach... How far do you think we are away from this?

I don't think it is a way to go. Runtime reflection adds
runtime overhead, which is hard to eliminate. On the
other hand, compile time reflection has no impact
on performance or memory usage and also it can be
easily converted to runtime reflection by providing
OO wrappers. What would be really useful is something
like restor suggested in this thread: ability to get tuple
of references to all members of a struct/class. But
I'm not aware of any proposals regarding this subject.

Regards,
Roman Perepelitsa.

Martijn Meijering

unread,
Dec 28, 2007, 1:44:07 PM12/28/07
to
Roman.Pe...@gmail.com wrote:
> I don't think it is a way to go. Runtime reflection adds
> runtime overhead, which is hard to eliminate. On the
> other hand, compile time reflection has no impact
> on performance or memory usage and also it can be
> easily converted to runtime reflection by providing
> OO wrappers.

Sure, I was thinking of compile-time reflection, which is why I would
like to be able to pass in a templated block to ForEach.

> What would be really useful is something
> like restor suggested in this thread: ability to get tuple
> of references to all members of a struct/class.

Agreed.

>But
> I'm not aware of any proposals regarding this subject.

Neither am I, but I think it would be quite an important addition. Not
quite as important as modules, but still quite important.

John Nagle

unread,
Dec 28, 2007, 4:46:27 PM12/28/07
to
Martijn Meijering wrote:
> Roman.Pe...@gmail.com wrote:

> > What would be really useful is something
>> like restor suggested in this thread: ability to get tuple
>> of references to all members of a struct/class.
>
> Agreed.
>
>> But
>> I'm not aware of any proposals regarding this subject.
>
> Neither am I, but I think it would be quite an important addition. Not
> quite as important as modules, but still quite important.

I'd once given this some thought. But in a language that doesn't
have tuples, and barely has arrays with known length, it's difficult to
create an appropriate data structure.

I suppose something could be hacked up involving recursive template
instantiation. One could have a primitive like like "typeof_field(T,N)",
returning the type of field N of object T. Then, using recursive
templates, one could iterate through the fields. It might also be
useful to have "field_count(T)", for termination checking.

This would be useful for automatically generating marshalling code
at compile time. That can be a substantial win, because marshalling code
usually consists of trivial copies slowed down by the run time machinery
which invokes them.

John Nagle
Animats

co...@mailvault.com

unread,
Jan 1, 2008, 4:21:37 AM1/1/08
to

I don't think you read the original post or his followup very closely.
He wants to avoid duplicating the types and names.

>
> Now you have, for example:
>
> AnotherClass c;
> save(c, myfile);
>
> save is a generic algorithm that can serialize serializable types, as
> long as they meet requirements.
> So with minimal code, you can serialize data. Next things are pointers
> and stl containers.
>

What is your rationale for this library? Have you done any
performance
tests with your stuff? There are a few between Boost serialization
and our
approach here - www.webebenezer.net. I think it makes sense for those
who are taking the library approach to work together. Right now you
are duplicating more than just decarations.

Brian Wood
Ebenezer Enterprises

Larry Evans

unread,
Jan 2, 2008, 1:08:20 AM1/2/08
to
On 12/20/07 15:44, Martijn Meijering wrote:
[snip]

> I was thinking that if we give type_info a virtual member ForEach, we
> could use it to loop over the elements of the type and do something
> appropriate. Now that I think more closely about it, I think that would
> require a combination of member templates and virtual functions, which
> is not possible at present and unlikely to be in future. Maybe you could
> do something with decltype. Or maybe it is harder than I think.
>
> I guess I'm just wondering how difficult it would be to add proper
> reflection to C++. It would be nice if you could pass a templatised
> closure to type_info.ForEach... How far do you think we are away from this?

The boost visit_each *may* provide you with more implementation clues:

http://www.boost.org/doc/html/boost/visit_each.html

quoting from there:

The visit_each mechanism allows a visitor to be applied to every
subobject in a given object.

HTH.

-regards,
Larry

Mathias Gaunard

unread,
Jan 4, 2008, 12:33:37 PM1/4/08
to
On 28 déc 2007, 22:46, na...@animats.com (John Nagle) wrote:

> I'd once given this some thought. But in a language that doesn't
> have tuples, and barely has arrays with known length, it's difficult to
> create an appropriate data structure.

There is no problem with C++ tuples. They're simply automatically-
generated structures with some reflection information (ability to know
the number of members, ability to retrieve the i-th member, ability to
retrieve the type of the i-th member).
But anyway why would you want to use tuples to expose full class
reflection? They're not enough to support all of the reflection needs
of C++ classes (member variables, overloaded member functions, static
member variables and functions, typedefs).

I believe this design is fairly good:

template<typename T>
struct reflection {};

template<> struct reflection<MyClass>
{
typedef mpl::map<
mpl::pair<
mpl::vector_c<char, 'm', 'e', 'm', 'b', 'e', 'r', '1'>,

a_function_object_type_which_allows_to_get_the_member_and_exposes_its_type
>,
....
> member_variables;

typedef .... member_functions; /* same as member_variables except
the function object must expose and allow to call multiple overloads
*/

typedef .... typedefs; /* nothing more than a type -> type map */
typedef .... static_member_functions; /* same as
member_functions, except we don't take an object in the functor
constructor */
typedef .... static_member_variables; /* same as
member_variables, except we don't take an object in the functor
constructor */

typedef .... constructors; /* a single function object */

typedef .... base_classes; /* a list of base types */
};

I'd say only public interface needs to be exposed, but protected and
private interfaces could also be exposed in a reflection_protected/
private for example.

The only problem is how to expose the type of template member
functions.
Doing so would be quite complicated.

For example, to encode
template<int A, typename B> typename B::type func(B&, void*),

we could expose the template parameters and then construct an
expression tree for each element of the signature.

typedef mpl::vector<
mpl::pair< mpl::vector_c<char, 'A'>, value_parameter<int> >,
mpl::pair< mpl::vector_c<char, 'B'>, type_parameter >
> parameters;

typedef mpl::vector<
static_var_bind< ref<1>, mpl::vector_c<char, 't', 'y', 'p', 'e'>
>, /* ref<1> stands for second template parameter */
add_ref< ref<1> >,
type<void*>
> signature;

with appropriate types providing reflection:
- value_parameter and type_parameter
- ref and type
- static_var_bind, static_func_bind, add_ref, add_const, add_volatile,
add_pointer, and probably others, such as passing the parameter as a
parameter to another template or building a function type which
contains a parameter type.

Another simpler but less powerful way would be to expose the template
parameters and then allow the signature to be extracted given the
parameters.

typedef mpl::vector<
mpl::pair< mpl::vector_c<char, 'A'>, value_parameter<int> >,
mpl::pair< mpl::vector_c<char, 'B'>, type_parameter >
> parameters;

template<int A, typename B>
struct signature
{
typedef typename B::type (B&, void*) type;
};

0 new messages