带参数和不带参数的 C++ 预处理器宏

问题描述 投票:0回答:1

我想根据宏调用是否带参数来调用两个不同的宏。基于SO上有关特定参数数量的许多示例,我想出了这个,但它并没有扩展

__VA_OPT__(_WITH_ARGS)

#define FUN() "call without arguments"
#define FUN_WITH_ARGS(...) "call with arguments"
#define GET_MACRO(b) FUN##b
#define CALL(...) GET_MACRO(__VA_OPT__(_WITH_ARGS))(__VA_ARGS__)

CALL() // --> "call without arguments"
CALL(5) // --> "call with arguments"

如何扩展

__VA_OPT__(_WITH_ARGS)
以便
CALL
调用
FUN
FUN_WITH_ARGS

编辑:修复了拼写错误 - 仍然无法在 MSVC 中工作。

c++ preprocessor variadic-macros
1个回答
0
投票

我对MSVC一无所知。

检测宏中零参数的常用方法是阅读 Jens Gustedt 的精彩博客 https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ ,复制他的代码并记住给予他信任。使用

ISEMPTY
宏,您可以根据扩展连接您的重载。

#define _ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
#define HAS_COMMA(...) _ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
#define _TRIGGER_PARENTHESIS_(...) ,
 
#define ISEMPTY(...)                                                    \
_ISEMPTY(                                                               \
          /* test if there is just one argument, eventually an empty    \
             one */                                                     \
          HAS_COMMA(__VA_ARGS__),                                       \
          /* test if _TRIGGER_PARENTHESIS_ together with the argument   \
             adds a comma */                                            \
          HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__),                 \
          /* test if the argument together with a parenthesis           \
             adds a comma */                                            \
          HAS_COMMA(__VA_ARGS__ (/*empty*/)),                           \
          /* test if placing it between _TRIGGER_PARENTHESIS_ and the   \
             parenthesis adds a comma */                                \
          HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/))      \
          )
 
#define PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define _ISEMPTY(_0, _1, _2, _3) HAS_COMMA(PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define _IS_EMPTY_CASE_0001 ,

#define CONCAT(a, b)  a##b
#define XCONCAT(a, b)  CONCAT(a, b)

#define FUN_1()     "call without arguments"
#define FUN_0(...)  "call with arguments"
#define CALL(...)   XCONCAT(FUN_, ISEMPTY(__VA_ARGS__))(__VA_ARGS__)

CALL() // --> "call without arguments"
CALL(5) // --> "call with arguments"

但是人们只是在

参数数量上的重载宏
中介绍的“通常”宏重载中使用##__VA_ARGS__。在较新的 C 预处理器中,我们可以使用
__VA_OPT__
代替 GNU 扩展。我使用的常用样式如下所示:

#define FUN_0()     "call without arguments"
#define FUN_1(...)  "call with arguments" 
#define CALL_N(_4,_3,_2,_1,N,...)  FUN_##N
#define CALL(...)  CALL_N(_0 __VA_OPT__(,) __VA_ARGS__,1,1,1,0)(__VA_ARGS__)

CALL() // --> "call without arguments"
CALL(5) // --> "call with arguments"
© www.soinside.com 2019 - 2024. All rights reserved.