This is not a good solution, but it can do the trick for you on simple functions. I still haven't expanded it for templates and other things like variable functions:
#define FUNCTION_DECL(R, N, ...) \ RN(__VA_ARGS__); #define DEFINE_FRIEND_OPERATOR(CLASS_NAME, MEMBERS) \ friend std::ostream& operator<<(std::ostream& s, CLASS_NAME const& f) \ { \ std::cout << #CLASS_NAME << ':' << std::endl; \ MEMBERS \ return s; \ } #define S_(X) #X #define S(X) S_(X) #define STREAM_FUNCTION(R, N, ...) \ s << " " #R " " #NS((__VA_ARGS__)) << std::endl;
I see no portable way to have a class name other than passing it to a macro, so the type is skipped.
Now you can put macros over the corresponding heading (and find the best / more suitable names ...) that will be included for each class. There you would:
class Foo { #define FOO_MEMBERS \ MEMBER(int, f0, int, int, int) \ MEMBER(double, f1, double) \ MEMBER(void, f2, char const) public: #ifdef MEMBER #undef MEMBER #endif #define MEMBER FUNCTION_DECL FOO_MEMBERS #undef MEMBER private: #define MEMBER STREAM_FUNCTION DEFINE_FRIEND_OPERATOR(Foo, FOO_MEMBERS) #undef MEMBER };
For map entries, you will have similar macros that generate an initialization list in the constructor, for example, here .
source share