问题
I want to generate serialization/deserialization code for
class Object
{
string a;
int b;
long c;
char d;
};
by looking at a mpl sequence, but I need to be able to identify object and retrieve it back as well, I can't figure out how would I get the names of it members, do I have to know it?
code should look like
void SerializeObject(ostream os)
{
serialize(object.a, os);
serialize(object.b, os);
//serialize(object.member, os);
}
I want to generate above code by user only defining a mpl sequence corresponding the object layout, is it doable, can you give me some hints?
my aim is:
User defines mpl::vector<String, int, long, char>
for above object and my metaprogram
can generate the coded needed.
回答1:
Consider a boost::fusion
, and use the macro BOOST_FUSION_ADAPT_STRUCT()
to promote your structure to a fusion sequence (random access), e.g. once you've defined the above structure, you can do something like
BOOST_FUSION_ADAPT_STRUCT(
Object,
(std::string, a)
(int, b)
(long, c)
(char, d)
)
Now that it's been promoted, you can simply use a for_each
to iterate over the members, something like:
template<typename archive>
struct serializer {
serializer(archive& ar):ar(ar) {}
template<typename T>
void operator()(const T& o) const {
ar & o; // assuming binary for example...
}
archive& ar;
};
template<typename archive, typename sequence>
void serialize(archive& ar, sequence const& v) {
boost::fusion::for_each(v, serializer<archive>(ar));
}
To use, it should be as simple as:
Object foo; // instance to serialize
serialize(<archive>, foo);
回答2:
There are no ways to infer member names in templates. You'll need to specify everything explicitly, like this:
template<typename ObjT, typename MemberT, MemberT ObjT::*Ptr>
struct member{};
mpl::vector
<
member<Object, string, &Object::a>,
member<Object, int, &Object::b>,
member<Object, long, &Object::c>,
member<Object, char, &Object::d>
>;
Another option is to create functions to help generate member
, define an operator>>
for member
that merges them into a member_vec
, and an operator>>
for member_vec
that merges into a larger member_vec
. Since you're only using the type, the compiler can optimize away any actual function calls
Functions can use implicit template arguments, so it can make serializers take a bit less code to define:
auto serializer =
mem(&Object::a) >>
mem(&Object::b) >>
mem(&Object::c) >>
mem(&Object::d);
I've made serializers myself, using both techniques. The second one is what I'm most happy with.
回答3:
You can use mpl::string
to represent member names. In my app, I do a little bit of code generation that emits something like the following.
typedef mpl::string < 'n', 'a', 'm', 'e' > name;
You can use the mpl::c_str < name >::value
to get the string representation. i.e. "name".
I store a sequence of such member names, another sequence for member pointers, zip them together and then use one of the boost::fusion query algorithms to find the member pointer for a given member name.
I'll post code if you are interested. Currently I don't have access to it since it is in my home PC.
来源:https://stackoverflow.com/questions/6022459/boost-mpl-to-generate-code-for-object-serialization