【问题标题】:Generate multiple macro calls according to the number of arguments根据参数数量生成多个宏调用
【发布时间】:2013-02-19 15:02:55
【问题描述】:

我试图以重复的方式多次调用此函数。

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

我写了以下宏:

#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)

等等……

我需要调用METADATA_METHODS_IMPL_N,其中N__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;\
}

上面的代码(带有BOOST_PP_OVERLOAD)给了我不合适的结果:

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

    METADATA_METHODS(F1, F2, F3);
};

这会导致

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; 
};

我想要这样的东西:

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; 
};
  • 有人知道如何达到预期的效果吗?
  • 我可以使用Boost.preprocessor 库为某些K in [1 .. 10] 使用METADATA_METHODS_IMPL_1 自动生成METADATA_METHODS_IMPL_K

【问题讨论】:

  • Variadic macro trick的可能重复
  • 这里有一些可以使用的东西:stackoverflow.com/questions/2308243/…
  • @PlasmaHH,我认为在回答第二个问题之前无法关闭该主题。不过,感谢您的帮助。一个下来,一个去:)
  • @maverik:这就是为什么在 SO 上将多个问题作为一个问题发布是不好的原因:我相信很多人也会忽略第二个问题。请记住,SO 也会保留问题供其他人查找;我建议您只需为第二个问题打开一个新问题,并在那里进行更详细的解释。
  • @PlasmaHH,你是对的。无论如何,我正在检查您建议的主题的答案。第二个对我不起作用(在 VS 2008 中)。

标签: c++ macros variadic-macros


【解决方案1】:

使用这些宏,我们可以使预处理器继续重新扫描并允许递归宏。

#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__

我们可以定义一些辅助函数来构建概念。

#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) 

并构建这个带有第一个参数的宏映射函数。

#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))

定义实现相关函数后

#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

这个:

METADATA_METHODS(metadata, F1, F2, F3);

结果(添加一些格式后):

METADATA_METHODS_IMPL(metadata, F1, "F1");
METADATA_METHODS_IMPL(metadata, F2, "F2");
METADATA_METHODS_IMPL(metadata, F3, "F3");
return metadata;

【讨论】:

    猜你喜欢
    • 2015-02-16
    • 2021-01-31
    • 2018-09-06
    • 2019-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多