Boost logo

Boost :

Subject: Re: [boost] [Boost-interest] C++ library for runtime-concepts (type-erasure)
From: Matus Chochlik (chochlik_at_[hidden])
Date: 2011-02-15 04:40:37


On Mon, Feb 14, 2011 at 7:36 PM, Germán Diago <germandiago_at_[hidden]> wrote:
>> 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.

This certainly may seem so from the point of view of your library.
But if you look at the bigger picture then you'll see that it will be
many times used in applications using other utilities and libraries,
some of which could also employ reflection, and then having a single
reflection facility that can provide meta-data for all of them is a great
advantage. The slight overhead of the compile-time part of Mirror
compared to what you are proposing is IMO worth it. The reusability
of meta-data provided by Mirror is one of its strong suits, if I may
say so :)

>
>> 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.

This is what the visitors in the old (non C++0x) version of Mirror were doing.
In the new version this will be implemented by special manipulator classes
that will be generated by a mechanism similar to the factory generator
that already is in Mirror.

This way you will be able to do not only serialization/marshaling-like
things but you'll be able to generate a (reusable) GUI for the inspection
or even manipulation of existing instances of every 'reflectible' type.

>
>
>>
>>>
>>> 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:

If you need just this I think you can use Boost.Fusion. But, the above
still applies. It focuses on a single task what makes the meta-data
unusable for some other purposes.

>>>
>>> class MyClass {
>>> typedef MyClass this_class;
>>>
>>> std::string val_;
>>> float f_;
>>> public:
>>> typedef std::tuple<MEM_VARS2(val_, f_)> serializable_members_t;
>>> };
>>>
>>
[snip]
>
>
>> 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>...

I've tried to use compile-time strings with Mirror twice, the first time
with MPL and the second time with C++0x variadic templates,
and the result was an increase in both compile-times and executable
size (somewhere between 3 to 7 percent depending on the usage).
Unless you really, really need to use a compile time string, consider
using a simple literal.

>
> 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.
>
[snip]

> - Enable 'building' types with arbitrary member variables. -> This one
> is pretty difficult.

I'm not sure if I understand correctly what you mean but if
you are referring to transforming something like this...

struct some_type
{
  T1 m1;
  T2 m2;
   ...
  Tn mn;
};

into

struct some_other_type
{
  transformed<meta_data<T1, m1> >::type m1;
  transformed<meta_data<T2, m2> >::type m2;
  ...
  transformed<meta_data<Tn, mn> >::type mn;
};

then it will be doable with Mirror (it actually already is
in the old version and partially also in the new one
but still undocumented).

BR,

Matus


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