preprocessor metaprogramming question

Hello, Here's a question for the preprocessor metaprogramming experts out there. I have some classes that need to have write() methods that look like this: template <typename output> bool write(output& out) const { return utils::write(out, member_1) && utils::write(out, member_2) && ... utils::write(out, member_n); } where member_1, member_2, ..., member_n are the member variables of the class. (These write() methods are used as part of a serialization framework). Since I have quite a few classes that need write() methods that look like this, and the structure of each write() method is uniform (the only thing that varies is the names of the class members), I figured that it would be neat to somehow generate the code for these write() methods. What I came up with is macros that look like this: #define MEMBERS1(m1) \ template <typename output> \ bool write(output& out) const \ { \ return utils::write(out, m1); \ } #define MEMBERS2(m1, m2) \ template <typename output> \ bool write(output& out) const \ { \ return utils::write(out, m1) && \ utils::write(out, m2); \ } // and so on for MEMBERS3, MEMBERS4, etc. Then, instead of declaring and defining the write() methods explicilty, I would just call the appropriate MEMBERS# macro in the class definition, e.g. for a class with 3 members named a, b, and c, I'd write MEMBERS3(a, b, c) in the class definition. While this is definitely an improvement over writing the write() methods explicitly for each class, there are two issues with it: 1) The number of lines of code needed to write the macro definitions is quadratic in the maximum number of parameters supported. It would be nice if it could be constant instead. 2) The user of the macros needs to match the macro name to the number of member variables in the class, and to change the macro name whenever the number of member variables changes. I'm wondering if there is a way to improve on this generation scheme that solves one or both of these issues. If I were allowed to use C++0x, I could have a variadic macro MEMBERS(...) and inside it pass the parameters to a variadic template function which unpacks its parameters and calls utils::write() on each. This would solve both issues. Unfortunately, however, I am not allowed to use C++0x features, since our code needs to be able to compile on our servers, which run Ubuntu 8.04, which runs g++ 4.2, which does not support C++0x features. So I thought I'd turn to some more preprocessor magic to solve these issues. I looked at examples in Boost.Preprocessor that generated repetitive code using preprocessor metaprogramming. However, all the examples there generated repetitive *code*, whereas what I seem to need is to be able to generate repetitive *macro definitions*. Is there a way to do that? If not, can anyone recommend other ways of improving the way I generate the code for the write() functions? Thanks in advance, Nate. _________________________________________________________________ Learn more ways to connect with your buddies now http://go.microsoft.com/?linkid=9734388

Instead of using shared_ptr for my async_recv's in Boost.Asio, it would be a lot more convenient if I could use unique_ptr instead. Does the library support move semantics, or are actual copies really needed? Regards, -- Clark

AMDG Nathan Ridge wrote:
Here's a question for the preprocessor metaprogramming experts out there.
I have some classes that need to have write() methods that look like this:
template <typename output> bool write(output& out) const { return utils::write(out, member_1) && utils::write(out, member_2) && ... utils::write(out, member_n);
}
where member_1, member_2, ..., member_n are the member variables of the class.
#include

From: watanabesj@gmail.com Nathan Ridge wrote:
Here's a question for the preprocessor metaprogramming experts out there.
I have some classes that need to have write() methods that look like this:
template <typename output> bool write(output& out) const { return utils::write(out, member_1) && utils::write(out, member_2) && ... utils::write(out, member_n);
}
where member_1, member_2, ..., member_n are the member variables of the class.
#include
#define WRITE(r, data, member) && utils::write(out, member)
#define MEMBERS(members) \ template<typename output> \ bool write(output& out) const \ { \ return true \ BOOST_PP_SEQ_FOR_EACH(WRITE, ~, members); \ }
MEMBERS((a)(b)(c))
Cool! I don't suppose there's any way to have the syntax be MEMBERS(a, b, c)? Thanks, Nate. _________________________________________________________________ MSN Dating: Find someone special. Start now. http://go.microsoft.com/?linkid=9734384

From: watanabesj@gmail.com To: boost-users@lists.boost.org Subject: Re: [Boost-users] preprocessor metaprogramming question
AMDG
Nathan Ridge wrote:
MEMBERS((a)(b)(c))
I don't suppose there's any way to have the syntax be MEMBERS(a, b, c)?
Not without variadic macros.
How would one do it using variadic macros? Thanks, Nate. _________________________________________________________________ Look 'em in the eye: FREE Messenger video chat http://go.microsoft.com/?linkid=9734386

AMDG Nathan Ridge wrote:
Nathan Ridge wrote:
MEMBERS((a)(b)(c))
I don't suppose there's any way to have the syntax be MEMBERS(a, b, c)?
Not without variadic macros.
How would one do it using variadic macros?
I don't know, as I've never tried to use variadic macros. There ought to be some way to figure out how many argument you have. Once you have that, you can use Boost.PP tuples or arrays. In Christ, Steven Watanabe

Date: Sun, 20 Jun 2010 18:02:16 -0700 From: watanabesj@gmail.com To: boost-users@lists.boost.org Subject: Re: [Boost-users] preprocessor metaprogramming question
AMDG
Nathan Ridge wrote:
Nathan Ridge wrote:
MEMBERS((a)(b)(c))
I don't suppose there's any way to have the syntax be MEMBERS(a, b, c)?
Not without variadic macros.
How would one do it using variadic macros?
I don't know, as I've never tried to use variadic macros. There ought to be some way to figure out how many argument you have. Once you have that, you can use Boost.PP tuples or arrays.
There appears to be no builtin way, but it turns out (http://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a...) you can write a macro that counts the number of arguments: #define PP_NARG(...) \ PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) #define PP_NARG_(...) \ PP_ARG_N(__VA_ARGS__) #define PP_ARG_N( \ _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ _61,_62,_63,N,...) N #define PP_RSEQ_N() \ 63,62,61,60, \ 59,58,57,56,55,54,53,52,51,50, \ 49,48,47,46,45,44,43,42,41,40, \ 39,38,37,36,35,34,33,32,31,30, \ 29,28,27,26,25,24,23,22,21,20, \ 19,18,17,16,15,14,13,12,11,10, \ 9,8,7,6,5,4,3,2,1,0 Is it possible to improve on this macro and write it in constant space with Boost.PP? Thanks, Nate. _________________________________________________________________ Turn down-time into play-time with Messenger games http://go.microsoft.com/?linkid=9734385
participants (3)
-
Clark Gaebel
-
Nathan Ridge
-
Steven Watanabe