
If you do not mind C++0x dependency and verbose macros, Boost.Mirror does this very well. Older versions of Boost.Mirror do not require C++0x and the developers of Boost.Mirror are also creating a tool that will auto-generate the required macros. My feeling is that if your code requires that much reflection and you are willing to use a pre-processor then chances are your compile times and binary sizes will become huge. If you are using a pre-processor then you might as well generate code directly rather than using templates and should probably be using a different language.
I looked at Boost.Mirror some time ago, but I think that, for my own goals, that is a too heavyweight dependency.
A simple version of run-time reflection, useful for serialization: It is funny you mention this, I am actively working on adding serialization features to Boost.IDL with the goal of providing more control over the 'Archive' format than Boost.Serialization. Specifically, I want to support JSON / Protocol Buffer serialization approach to support forward/backward compatibility.
I think that Boost.serialization library is a good library, but if it were written nowadays, it would be done in another way. I think that the correct way when c++0x is implemented with some trait that identifies the members that you want to serialize, and, after that, return an in-memory object, like a string. Having the information provided by those members, you could implement generic and custom serializations: binary, json, and whatever, without having to code a special-purpose format for your specific library. This way we can make libraries useful to more people.
I tried (but it's incomplete) a new reflection approach, and I think that with c++0x will be possible. The goal for this reflection library was serialization, so it wasn't a general reflection framework, but it was good enough to serialize objects.
My approach was to use a tuple that described every c++ member that a class had. It looked something like this:
class MyClass { typedef MyClass this_class;
std::string val_; float f_; public: typedef std::tuple<MEM_VARS2(val_, f_)> serializable_members_t; };
I suspect that your tuple approach could be combined with my visitor approach to offer two methods of reflection, runtime and compile time:
Yes, I think it could be possible. Generating the runtime information from the compile-time information is the right approach to not duplicate things. The only downside is that you still have to make some kind of registration for every type, but that could be as simple as a single macro.
The trouble is that even though we have compile time access to all of the member pointers, we have lost the 'name'. With some fancy magic to generate a const char* with external linkage one might be able to get the name into the template parameter as non-type template parameter.
With constexpr + user-defined literals, I think this can be done: template <char...C> struct Var_Name { //expand here C... }; And with user-defined literals: constexpr template <char... C> Var_Name<C...> operator _var(); now: //We didn't loose the name!!!! Good c++0x... typedef tuple<Var_Name<"name"_var>... This should be valid c++0x.
Even if you achieved complete static reflection with the above method, it would still not enable you to 'build' types with arbitrary member variables and methods. Perhaps using boost::fusion fused parameters you could simplify the number of permutations enough that it may be possible to generate a 'class' that given a method signature template parameter implements 'name' in terms of that signature.
I think that's not possible in c++, but I'll try to investigate once I have some time.
Correct me if I am wrong, but doesn't boost::fusion::vector<> explode compile times as the number of elements grows? Is tuple better? Would attempting to reflect an type with 50 fields in this manner be totally unfeasible?
I haven't tried those tests, but maybe it would take too long. It's just the idea I was implementing and that I had in my mind, but I don't know wether its compile-times are practical.
Your ideas are good in theory and they are my ideal as well, but I have yet to reduce it to practice. Any ideas on that would be useful.
So, to summarize, we need: -Static Type information -> Useful for serialization (I think that boost.Serialization library is aging in this regard, although very useful still today). I would try with a tuple trait approach. -Type erasure. -> I'm trying to implement this one, and I think a nice library can be built in c++/c++0x. -RPC. -> This could be based in information registered for functions through metaprogramming and pointer to member registration. - Enable 'building' types with arbitrary member variables. -> This one is pretty difficult.