提取__VA_ARGS__的第一个参数

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

假设我有一个宏:

#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时进行评估。

c++ c++17
2个回答
2
投票

我建议使用通用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来分离函数调用。
  • 我们也可以使用从C ++ 17为if(a)引入的初始化器来应用if语句。

然后提出的宏如下。这也适合你。

DEMO

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

1
投票

基于这个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__))
© www.soinside.com 2019 - 2024. All rights reserved.