Оцените аргумент макроса перед обработкой - PullRequest
0 голосов
/ 26 сентября 2019

Я хочу иметь возможность генерировать эти опции из макроса:

  1. if(void* temp = func(arg)){ foo(temp, variable);return; }
  2. if(void* temp = func2(arg)){ foo(temp, variable2);return; }
  3. if(void* temp = func3(arg)){ foo(temp, variable3);return; }

И так далее, но, как вы видите, 1 является единственным частным случаем.

Я хочу написать макрос, который принимает число в качестве параметра и генерируетзаштрихуйте этот код, возможно, числами, намного превышающими 3. К сожалению, это требует построения в особом случае, если пользователь передал 1, и осуществления общего случая, если они передали любое другое число.Есть ли способ сделать это?

1 Ответ

1 голос
/ 27 сентября 2019

Если вы действительно хотите использовать CPP для этого, это достаточно просто.Косвенный макрос GLUE и косвенный макрос SECOND являются основными инструментами, которые вы можете использовать:

#define GLUE(A,B) GLUE_I(A,B)
#define GLUE_I(A,B) A##B
#define SECOND(...) SECOND_I(__VA_ARGS__,,)
#define SECOND_I(_,X,...) X

Косвенный SECOND позволяет вам сопоставить шаблон в препроцессоре.Способ, который работает, заключается в том, что вы создаете первый токен, который обычно просто одноразовый.Но поскольку расширение является косвенным, если первый созданный вами токен является макросом, он будет расширяться первым (а именно, как часть подстановки аргумента для переменной).Если это расширение содержит запятую, оно может сдвинуть «новый» второй аргумент прямо перед тем, как косвенное указание выберет второй.Вы можете использовать это для создания своих особых случаев.

Вот средство сопоставления с образцом cpp, использующее эту конструкцию, которая возвращает свой аргумент, если только он не равен 1, и в этом случае он расширяется без токенов:

#define NOT_ONE(N) SECOND(GLUE(TEST_IF_1_IS_,N),N)
#define TEST_IF_1_IS_1 ,

Используя это, ваш макрос может быть:

#define DISPATCH_CASE(N) \
   if(void* temp = GLUE(func,NOT_ONE(N))){ \
      foo(temp, GLUE(variable,NOT_ONE(N))); \
      return;
   }

Демо (coliru)

Обновление: версия Visual Studio

Но я работаю в Visual Studio и не могу заставить его работать.Я думаю, что проблема в том, что расширение __VA_ARGS__ работает по-разному в Visual Studio

. Для VS я обнаружил еще один уровень косвенности определенного вида (тот, который отделяет макрос от его аргументов, так что список аргументов может вычисляться впростой контекст (...) до его применения) помогает определить, какие аргументы разделены запятыми.Как правило, я бы повторял один и тот же шаблон в нескольких макросах, чтобы избежать синей краски.

Здесь это означает немного уродливее:

#define GLUE(A,B) GLUE_C(GLUE_I,(A,B))
#define GLUE_I(A,B) A##B
#define GLUE_C(A,B) A B
#define SECOND(...) SECOND_C(SECOND_I,(__VA_ARGS__,,))
#define SECOND_I(_,X,...) X
#define SECOND_C(A,B) A B

Демо (goldbolt)

...