Сохранение определений препроцессора

Возможный дубликат:
Могу ли я переопределить макрос С++ и определить его обратно?

Скажем, у меня есть код, который использует имя BLAH для переменной. Предположим, что BLAH - это общее определение препроцессора во многих стандартных файлах заголовков (определено как 10), поэтому, если мой файл включен после любого из них, код разбивается, потому что BLAH преобразуется в 10; поэтому я должен #undef BLAH. Но и другие заголовки могут зависеть от BLAH, поэтому я должен восстановить BLAH его исходное значение после завершения моего заголовка. Можно ли сделать что-то вроде этого:

#ifdef BLAH
#define BLAH_OLD BLAH
#undef BLAH
#endif

... code ...

// restore BLAH to 10
#ifdef BLAH_OLD
#define BLAH BLAH_OLD
#end

? Это не работает, конечно, потому что BLAH не расширен до 10. Я пробовал делать что-то вроде

#define EXPAND_AGAIN(x) x
#define EXPAND(x) EXPAND_AGAIN(x)
#define BLAH_OLD EXPAND(BLAH)

но это тоже не работает, поскольку EXPAND воспринимается буквально и не расширяется. Я использую MSVC 2008/2010, но было бы прекрасно, если бы решение работало и на большинстве других компиляторов.

Ответ 1

Да, учитывая, что ваш компилятор поддерживает директивы макроса push/pop (визуальные С++, gcc, llvm all do):

#define BLAH 10

#pragma push_macro("BLAH")
#undef BLAH

#define BLAH 5

...

#pragma pop_macro("BLAH")

Ответ 2

К сожалению, препроцессор не поддерживает стек определений.

Библиотека препроцессора Boost позволяет препроцессору делать то, о чем вы никогда не думали, что это могло бы сделать (например, эффективные вариативные макросы в С++ 98), но связано с присущими ему препроцессорами ограничениями, поэтому никто не может этого сделать, извините.

Единственное известное средство полузащиты - зарезервировать ALL_UPPERCASE_IDENTIFIERS для макросов и постоянно использовать их для макросов. Это несколько уменьшает проблему столкновения имен. К сожалению, стандартная библиотека C определяет несколько строчных макросов или допускает их существование, например, assert, но их всего несколько.

С практической точки зрения основная проблема заключается в программировании Windows, где заголовок Microsoft [windows.h] определяет zillions макросов, отличных от верхнего регистра, включая по умолчанию min и max, которые конфликтуют с С++ стандартная библиотека.

Итак, для программирования на Windows С++ всегда указывайте NOMINMAX перед включением [windows.h].

Приветствия и hth.,

Ответ 3

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

Ответ 4

Один трюк, который работает для меня, - это использование перечисления в классе.

class foo
{
public:
  enum { blah = 10 } myenum;
}

Затем вы можете просто использовать

foo:blah

когда вам нужно "10".

Так как это часть класса, то другие применения "бла" не будут конфликтовать, и вы сохраните все, что def'ing и undef'ing.