Извлечение первого параметра из __VA_ARGS__ - PullRequest
0 голосов
/ 03 декабря 2018

Предположим, у меня есть макрос:

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

IЯ пытался решить эту проблему с той же идеей, что и BOOST_PP_VARIADIC_SIZE, но оказалось, что этот макрос возвращает 1 для BOOST_PP_VARIADIC_SIZE() (пустые аргументы), что не ожидается (я ожидал 0).

Обратите внимание, что мне нужно решение, где b и <some_parameters> оцениваются только тогда, когда bool(a) равно true.

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

Я предлагаю вариационный макрос с обобщенной лямбдой в качестве решения.Важными моментами являются следующие:

  • Трудно передать и a, и __VA_ARGS__ в лямбду в качестве переданных аргументов в макросе, потому что когда __VA_ARGS__ пусто

    [](){...}(a, __VA_ARGS__)
    

    становится

    [](){...}(a,)
    

    , и это , приводит к ошибке компиляции. Таким образом, мы разбиваем первый и второй аргументы FOO на захваченный и переданный соответственно соответственно следующим образом. Тогда мы можем использовать общую лямбду в макросе, даже если __VA_ARGS__ пуст.

    [a](){...}(__VA_ARGS__)
    
  • Размер __VA_ARGS__ можно оценить во время компиляции как constexpr auto N.Затем мы можем использовать if constexpr для разделения вызовов функций.

  • Мы также можем применить if с оператором инициализатора , который введен из C ++ 17 для if(a).

Тогда предлагаемый макрос выглядит следующим образом.Это также работает для вас.

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__)
0 голосов
/ 03 декабря 2018

Исходя из этого ответа , я мог бы решить проблему:

#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__))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...