0

I'm trying to call this function several times in a repeditive fashion.

template<class T>
void METADATA_METHODS_IMPL(std::string& metadata, const T &value, const std::string &key)
{
    metadata += boost::format("%1%:%2%") % key % value();
}

I have written the following macro:

#define METADATA_METHODS_IMPL_1(md, v1)\
   METADATA_METHODS_IMPL(md, v1, #v1);

#define METADATA_METHODS_IMPL_2(md, v1, v2)\
   METADATA_METHODS_IMPL_1(md, v1)\
   METADATA_METHODS_IMPL_1(md, v2)

#define METADATA_METHODS_IMPL_3(md, v1, v2, v3)\
   METADATA_METHODS_IMPL_2(md, v1, v2)\
   METADATA_METHODS_IMPL_1(md, v3)

and so on ...

I need to call METADATA_METHODS_IMPL_N where N is a number of arguments in __VA_ARGS__

#define METADATA_METHODS(...)\
std::string METADATA_METHODS_IMPL_FUNC()\
{\
    std::string metadata;\
    BOOST_PP_OVERLOAD(METADATA_METHODS_IMPL_,__VA_ARGS__)(metadata, __VA_ARGS__)\
    return metadata;\
}

The code above (with BOOST_PP_OVERLOAD) gives me unsuitable result:

class X
{
    std::string F1();
    std::string F2();
    std::string F3();

    METADATA_METHODS(F1, F2, F3);
};

This results in

std::string METADATA_METHODS_IMPL_FUNC() 
{
    std::string metadata; 
    METADATA_METHODS_IMPL(metadata, F1, F2, F3, "F1", "F2", "F3"); 
    METADATA_METHODS_IMPL(metadata, , ""); 
    METADATA_METHODS_IMPL(metadata, , ""); 
    return metadata; 
};

And I want something like this:

std::string METADATA_METHODS_IMPL_FUNC() 
{
    std::string metadata; 
    METADATA_METHODS_IMPL(metadata, F1, "F1"); 
    METADATA_METHODS_IMPL(metadata, F2, "F2"); 
    METADATA_METHODS_IMPL(metadata, F3, "F3"); 
    return metadata; 
};
  • Does anyone know how to achieve the desired result?
  • Can I use Boost.preprocessor library to automagically generate METADATA_METHODS_IMPL_K for some K in [1 .. 10] using METADATA_METHODS_IMPL_1
unDeadHerbs
  • 1,306
  • 1
  • 11
  • 19
maverik
  • 5,508
  • 3
  • 35
  • 55
  • 1
    possible duplicate of [Variadic macro trick](http://stackoverflow.com/questions/5365440/variadic-macro-trick) – PlasmaHH Feb 19 '13 at 15:11
  • 1
    Here's something that can be of use: http://stackoverflow.com/questions/2308243/macro-returning-the-number-of-arguments-it-is-given-in-c – StoryTeller - Unslander Monica Feb 19 '13 at 15:13
  • @PlasmaHH, I think the topic cannot be closed until the second question will be answered. Thanks for the help, though. One down, one to go :) – maverik Feb 19 '13 at 15:17
  • @maverik: This is why it is bad to post multiple questions as one on SO: I am sure many people will also simply overlook that there is a second question. Remember that SO preserves questions for others to find too; I would suggest you simply open a new question for your second one, and explain it in more detail there. – PlasmaHH Feb 19 '13 at 15:28
  • @PlasmaHH, you're right. Anyway, I'm checking the answers from the topic you suggested. The second one doesn't work for me (in VS 2008). – maverik Feb 19 '13 at 15:30
  • @maverik: afaik vs2008 doesn't implement the preprocessor very well in that regard; learn how to look at the preprocessed code in your compiler (always a good idea) and play with it, step by step. – PlasmaHH Feb 19 '13 at 15:32
  • @PlasmaHH, already doing that. I have no problems with boost.pp library (already wrote some things) in VS 2008, but can't figure out how to solve this question using boost.pp (lack of examples in this library makes me sad, nobody knows nothing) – maverik Feb 19 '13 at 15:36
  • @PlasmaHH, I don't know why but VS here `METADATA_METHODS(F1, F2, F3)` treats `F1, F2, F3` as one argument, so `VA_NARGS` results in `1` and function call is `METADATA_METHODS_IMPL(metadata, F1, F2, F3, "F1, F2, F3")` :( Can't find the way out – maverik Feb 19 '13 at 16:00

1 Answers1

0

Using these macros we can cause the preprocessor to keep rescanning and allow for recursive macros.

#define EVAL(...)  EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL3(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL0(EVAL0(EVAL0(__VA_ARGS__)))
#define EVAL0(...) __VA_ARGS__

We can define some helper functions to build up concepts.

#define CAT(a, ...) PRIMITIVE_CAT(a,__VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__

#define EMPTY()
#define EAT(...)
#define IDENT(...) __VA_ARGS__
#define DEFER(id) id EMPTY()
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)()   

#define I_TRUE(t,f) t
#define I_FALSE(t,f) f
#define I_IS_DONE(a,b,...) b
#define TRUE_DONE() ~, I_TRUE
#define IS_DONE(b) OBSTRUCT(I_IS_DONE)(CAT(TRUE_,b)(),I_FALSE) 

And build this Macro Mapping function that carries the first parameter to each.

#define MM() MM_CALL
#define MM_NEXT(Macro,md,a,...) \
  IS_DONE(a)(                    \
     EAT                          \
  ,                                \
     OBSTRUCT(MM)()                 \
  )                                  \
  (Macro,md,a,__VA_ARGS__)
#define MM_CALL(Macro,md,a,...)   \
  Macro(md,a)                      \
  MM_NEXT(Macro,md,__VA_ARGS__)
#define MacroMap(Macro,md,...) EVAL(MM_CALL(Macro,md,__VA_ARGS__,DONE))

After defining the implementation related functions

#define METADATA_METHODS_IMPL_MACRO(md,a) \
  METADATA_METHODS_IMPL(md, a, #a);

#define METADATA_METHODS(md,...) \
  MacroMap(METADATA_METHODS_IMPL_MACRO,md,__VA_ARGS__) \
  return md

This:

METADATA_METHODS(metadata, F1, F2, F3);

Results in this (after adding some formatting):

METADATA_METHODS_IMPL(metadata, F1, "F1");
METADATA_METHODS_IMPL(metadata, F2, "F2");
METADATA_METHODS_IMPL(metadata, F3, "F3");
return metadata;
unDeadHerbs
  • 1,306
  • 1
  • 11
  • 19