Могу ли я переопределить макрос С++ и определить его обратно?

Я использую в своем коде как библиотеку JUCE, так и ряд заголовков Boost. Juce определяет "T" как макрос (стон), а Boost часто использует "T" в своих определениях шаблонов. В результате, если вы каким-то образом включаете заголовки JUCE перед заголовками Boost, препроцессор расширяет макрос JUCE в коде Boost, а затем компилятор безнадежно теряется.

Сохранение моих включений в правильном порядке в большинстве случаев непросто, но может быть сложно, если у вас есть класс JUCE, который включает некоторые другие классы, а где-то в цепочке один файл включает Boost, и если какой-либо из файлы, прежде чем понадобится JUCE, включите в себя проблемы.

Моя первоначальная надежда на фиксацию этого была в

#undef T

перед тем, как включить в Boost. Но проблема в том, что если я не переопределяю его, тогда другой код путается, что "T" не объявлен.

Тогда я подумал, что, возможно, я мог бы сделать круговой трюк #define, например:

// some includes up here
#define ___T___ T
#undef T
// include boost headers here
#define T ___T___
#undef ___T___

Уродливо, но я думал, что это может сработать.

К сожалению нет. Я получаю ошибки в местах с использованием "T" в качестве макроса, который

'___T___' was not declared in this scope.

Есть ли способ, чтобы эти две библиотеки работали надежно вместе?

Ответы

Ответ 1

Как отметил greyfade, трюк ___T___ не работает, потому что препроцессор - довольно простое существо. Альтернативный подход заключается в использовании директив pragma:

 // juice includes here
 #pragma push_macro("T")
 #undef T
 // include boost headers here
 #pragma pop_macro("T")

Это должно работать в MSVС++, а GCC добавила поддержку pop_macro и push_macro для совместимости с ним. Технически это зависит от реализации, но я не думаю, что существует стандартный способ временного подавления определения.

Ответ 2

Можете ли вы обернуть библиотеку оскорблений в другой include и уловить #define T внутри?

например:

JUICE_wrapper.h:     
#include "juice.h"
#undef T

main.cpp:    
#include "JUICE_wrapper.h"    
#include "boost.h"

 rest of code....

Ответ 3

Тогда я подумал, что, возможно, я мог бы сделать круговой трюк #define, например:

Препроцессор C не работает таким образом. Символы препроцессора не определены в том же смысле, что символ имеет значение, когда, например, вы определяете функцию.

Это может помочь подумать о препроцессоре как о механизме замены текста. Когда символ определен, он обрабатывается как прямое текстовое замещение до конца файла или до него undefined. Его значение не хранится нигде и поэтому не может быть скопировано. Поэтому единственный способ восстановить определение T после того, как вы #undef ed, это полностью воспроизвести его значение в новой #define позже в вашем коде.

Лучшее, что вы можете сделать, это просто не использовать Boost или просить разработчиков JUCE не использовать T в качестве макроса. (Или, в худшем случае, исправьте это сами, изменив имя макроса.)