макрос зависимый макрос - PullRequest
5 голосов
/ 08 февраля 2011

Можно ли сделать что-то вроде этого:

  #define F(x) \
    #ifdef DOUBLE \
      2*x \
    #else \
      x \
    #endif

, чтобы, когда я использую F, то, во что оно расширяется, зависит от того, определен макрос DOUBLE?Я так не думаю, но я надеюсь.GNU-расширения хороши.

Edit В ответ на некоторые ответы я действительно использую это для генерации кода, где код немного отличается в зависимости от того, где он определен,Из-за порядка, в котором некоторые файлы включены, и где необходимо определить соответствующие макросы, переключение таким образом требует некоторого факторинга.Возможно, мне придется это сделать, но я был бы рад, если бы мне не пришлось неокрашиваться из этого угла!

Ответы [ 4 ]

13 голосов
/ 08 февраля 2011

Что не так с

#ifdef DOUBLE
  #define F(x) (2 * (x))
#else
  #define F(x) (x)
#endif
8 голосов
/ 08 февраля 2011

Если мы сможем ограничить проблему, вы можете сделать это. В частности, если вы можете гарантировать, что DOUBLE равен либо

  • не определен как макрос или
  • определяется как макрос, который расширяется до пустой последовательности токенов (например, #define DOUBLE),

тогда вы можете использовать косвенный подход с конкатенацией токенов:

#define F_IMPL_(x)       DOUBLE_IS_DEFINED
#define F_IMPL_DOUBLE(x) DOUBLE_NOT_DEFINED

#define F_1(x, m) F_2(x, m)
#define F_2(x, m) F_IMPL_ ## m ( x )

#define F(x) F_1(x, DOUBLE)

Пример использования:

F(t)
#define DOUBLE
F(t)

Результат после предварительной обработки:

DOUBLE_NOT_DEFINED
DOUBLE_IS_DEFINED

Этот подход также будет работать, если DOUBLE (если он определен) определен как макрос, который расширяется до одного известного токена, если этот токен может образовывать часть идентификатора (например, TRUE или 1 ). Чтобы справиться с этим, вам просто нужно переименовать макрос F_IMPL_ в F_IMPL_{TOKEN} (например, F_IMPL_TRUE или F_IMPL_1).

4 голосов
/ 08 февраля 2011

Почему бы не сделать вложение наоборот?

#ifdef DOUBLE
#define F(x) (2*(x))
#else
#define F(x) (x)
#endif 
3 голосов
/ 08 февраля 2011

Нет.Самое близкое, что вы можете сделать, это поместить это в заголовочный файл и #include этот заголовочный файл каждый раз, когда определения, которые вас интересуют, меняются.Это иногда называют шаблоном «X», поскольку X используется в качестве макроса, который изменяет определение.

Например, одним из распространенных применений этого шаблона является автоматическое создание имен строк значений перечисления:

// File myenum_values.h
// NOTE: _no_ header guards so we can include this file multiple times
X(Apple)
X(Orange)
X(banana)

// File myenum.h
enum Fruit
{
#define X(x) x,
#include "myenum_values.h"
}

const char *FruitNames[] =
{
#undef X
#define X(x) #x,
#include "myenum_values.h"
};

// We now have an array of fruit names without having to define the enum twice
...