On Wed, 26 Sep 2012 07:52:24 +0200,
I have a question about the use of the preprocessor library. I'll describe my ultimate goal in a moment, but I've simplified my first problem to the following. Also, I know what I'm doing looks a lot at first glance like Fusion's ADAPT_STRUCT, but I took a quick look at that documentation and I don't think it matches. However, if you disagree with me and think it does, or can suggest a totally different solution, feel free to describe how.
== My problem ==
I don't like C's struct syntax, so I'm trying to define my own. (</sarcasm> Really for purposes of this section I'm just doing this to figure out all the steps I'll need.)
What I want to do is something like the following:
#include
#define DEFINE_FIELD(r, os, field_pair) [....]
#define DEFINE_STRUCT(struct_name, fields) \ struct struct_name { \ BOOST_PP_SEQ_FOR_EACH(DEFINE_FIELD, ~, fields) \ }
DEFINE_STRUCT(mystruct, (int, x)(int, y)(double, z))
but this doesn't work, because the sequence is made up of pairs instead of single preprocessor arguments. (GCC complains about "macro "BOOST_PP_SEQ_SIZE_0" passed 2 arguments, but takes just 1" and same for PP_EXPR_IIF_0.)
I can get it to work by double-parenthesizing the stuff in the sequence (saying "((int, x))((int, y))((double, z))") then defining DEFINE_FIELD as follows:
#define DEFINE_FIELD_REAL(type, name) type name; #define DEFINE_FIELD(r, os, field_pair) DEFINE_FIELD_REAL field_pair
but this is less than optimal. Is there a way that I can do this easily, or would I effectively have to re-implement SEQ_FOR_EACH? (And how hard would that be if it's necessary?)
== What I'm actually trying to do ==
What I'm actually doing is trying to write a macro that will define a function like the following:
DEFINE_SERIALIZED_STRUCT(mystruct, (int, x)(int, y)(double, z)) | V struct mystruct { int x; int y; double z; }; void serialize(ostream & os, mystruct const & s) { os << "x: " << s.x << "\n"; os << "y: " << s.y << "\n"; os << "z: " << s.z << "\n"; }
(I didn't see a way to recover the field names from a Fusion-adapted struct -- from what I can tell, it more just seems to be a way to iterate over the fields.)
Hi, the trick /I looked from fusion:)/ is to wrap every sequence member in an additional () before passing it to the main macro: #define MY_SEQUENCE_CREATOR_0(...) \ ((__VA_ARGS__)) MY_SEQUENCE_CREATOR_1 #define MY_SEQUENCE_CREATOR_1(...) \ ((__VA_ARGS__)) MY_SEQUENCE_CREATOR_0 #define MY_SEQUENCE_CREATOR_0_END #define MY_SEQUENCE_CREATOR_1_END And then you wrap call to your DEFINE_STRUCT: #define _DEFINE_STRUCT(struct_name, fields) \ struct struct_name { \ BOOST_PP_SEQ_FOR_EACH(DEFINE_FIELD, ~, fields) \ } #define DEFINE_FIELD(r, data, field_tuple) \ V_BOOST_PP_TUPLE_ELEM(0, field_tuple) V_BOOST_PP_TUPLE_ELEM(1, field_tuple); #define DEFINE_STRUCT(struct_name, fields) \ _DEFINE_STRUCT(struct_name, \ BOOST_PP_CAT(MY_SEQUENCE_CREATOR_0 fields,_END)) \ If I dont mistake it basically transforms DEFINE_STRUCT(mystruct, (int, x)(int, y)(double, z)) into _DEFINE_STRUCT(mystruct, ((int, x))((int, y))((double, z))) so you get a single *tuple* as a parameter to your DEFINE_FIELD. Eventually you can call another macro with this tuple, but I am not sure whether this will be preprocessed as expected. I had troubles with it, so I used V_BOOST_PP_TUPLE_ELEM (appeared first in boost 1.49) to extract tuple elements in-place and it worked for me. // I've heard there are some nasty troubles with msvc and variadic macros, so you have an additional quest if you need to support msvc -- Slava