假设我有一个宏:
#define FOO(a, ...) if (a) foo(a, ## __VA_ARGS__)
这很好用:
FOO(a)
将转变为if (a) foo(a)
FOO(a, <some_parameters>)
将转变为if (a) foo(a, <some_parameters>)
是否可以修改此宏,因此只有__VA_ARGS__
的第一个参数(如果存在)传递给foo
?所以,我需要:
FOO(a)
将转变为if (a) foo(a)
FOO(a, b, <some_parameters>)
将转变为if (a) foo(a, b)
我试图用与BOOST_PP_VARIADIC_SIZE
相同的想法解决这个问题,但事实证明这个宏为1
(空参数)返回BOOST_PP_VARIADIC_SIZE()
,这是不可预期的(我期望0
)。
请注意,我需要一个解决方案,其中b
和<some_parameters>
仅在bool(a)
为true
时进行评估。
我建议使用通用lambda作为解决方案的可变宏。重点如下:
a
和__VA_ARGS__
传递给lambda作为宏中传递的参数,因为当__VA_ARGS__
为空时
[](){...}(a, __VA_ARGS__)
变
[](){...}(a,)
而这个,
导致编译错误。因此,我们将FOO
的第一个和第二个参数分别分为捕获的和传递的参数,如下所示。然后我们可以在宏中使用泛型lambda,即使__VA_ARGS__
为空。
[a](){...}(__VA_ARGS__)
__VA_ARGS__
的大小可以在编译时评估为constexpr auto N
。然后我们可以使用if constexpr
来分离函数调用。if(a)
引入的初始化器来应用if语句。然后提出的宏如下。这也适合你。
#include <tuple>
#define FOO(a, ...) \
if(const bool a_ = (a); a_) \
[a_](auto&&... args) \
{ \
const auto t = std::make_tuple(std::forward<decltype(args)>(args)...); \
constexpr auto N = std::tuple_size<decltype(t)>::value; \
\
if constexpr( N==0 ) { \
return foo(a_); \
} \
else { \
return foo(a_, std::get<0>(t)); \
} \
}(__VA_ARGS__)
基于这个answer,我可以解决这个问题:
#define PRIVATE_CONCAT(a, b) a ## b
#define CONCAT(a, b) PRIVATE_CONCAT(a, b)
#define GET_100TH( \
_01, _02, _03, _04, _05, _06, _07, _08, _09, _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, _64, _65, _66, _67, _68, _69, _70, \
_71, _72, _73, _74, _75, _76, _77, _78, _79, _80, \
_81, _82, _83, _84, _85, _86, _87, _88, _89, _90, \
_91, _92, _93, _94, _95, _96, _97, _98, _99, PAR, \
...) PAR
#define HAS_PARAMETER(...) GET_100TH(placeholder, ##__VA_ARGS__, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 0)
#define FIRST_PARAMETER_WITH_PREPENDED_COMMA0(...)
#define FIRST_PARAMETER_WITH_PREPENDED_COMMA1(a, ...) , a
#define FIRST_PARAMETER_WITH_PREPENDED_COMMA(...) CONCAT(FIRST_PARAMETER_WITH_PREPENDED_COMMA, HAS_PARAMETER(__VA_ARGS__))(__VA_ARGS__)
#define FOO(a, ...) if (a) foo(a FIRST_PARAMETER_WITH_PREPENDED_COMMA(__VA_ARGS__))