Ответ 1
Да, учитывая, что ваш компилятор поддерживает директивы макроса push/pop (визуальные С++, gcc, llvm all do):
#define BLAH 10
#pragma push_macro("BLAH")
#undef BLAH
#define BLAH 5
...
#pragma pop_macro("BLAH")
Возможный дубликат:
Могу ли я переопределить макрос С++ и определить его обратно?
Скажем, у меня есть код, который использует имя 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, но было бы прекрасно, если бы решение работало и на большинстве других компиляторов.
Да, учитывая, что ваш компилятор поддерживает директивы макроса push/pop (визуальные С++, gcc, llvm all do):
#define BLAH 10
#pragma push_macro("BLAH")
#undef BLAH
#define BLAH 5
...
#pragma pop_macro("BLAH")
К сожалению, препроцессор не поддерживает стек определений.
Библиотека препроцессора Boost позволяет препроцессору делать то, о чем вы никогда не думали, что это могло бы сделать (например, эффективные вариативные макросы в С++ 98), но связано с присущими ему препроцессорами ограничениями, поэтому никто не может этого сделать, извините.
Единственное известное средство полузащиты - зарезервировать ALL_UPPERCASE_IDENTIFIERS
для макросов и постоянно использовать их для макросов. Это несколько уменьшает проблему столкновения имен. К сожалению, стандартная библиотека C определяет несколько строчных макросов или допускает их существование, например, assert
, но их всего несколько.
С практической точки зрения основная проблема заключается в программировании Windows, где заголовок Microsoft [windows.h] определяет zillions макросов, отличных от верхнего регистра, включая по умолчанию min
и max
, которые конфликтуют с С++ стандартная библиотека.
Итак, для программирования на Windows С++ всегда указывайте NOMINMAX
перед включением [windows.h].
Приветствия и hth.,
Раньше я верил, что тот самый трюк, который вы пробовали, работает, поскольку я использовал его сам. Но в конце концов я узнал, что на самом деле это вообще не работает. Простым ответом является НЕТ, вы не можете сохранить текущее значение определения, изменить его, а затем восстановить старое значение. Препроцессор просто не работает. После того, как вы определите новое значение, старое значение исчезнет.
Один трюк, который работает для меня, - это использование перечисления в классе.
class foo
{
public:
enum { blah = 10 } myenum;
}
Затем вы можете просто использовать
foo:blah
когда вам нужно "10".
Так как это часть класса, то другие применения "бла" не будут конфликтовать, и вы сохраните все, что def'ing и undef'ing.