У меня есть макрос, используемый вокруг оператора кода, чтобы ввести обработку вложенных исключений:
#define TRAP_EXCEPTION(statement) \
try \
{ \
try{statement} \
catch(Engine::Exception& e) \
{ \
throw MyException(e.message()); \
} \
}
Это работало хорошо, пока в одном случае не возникли ошибки компилятора. Мне удалось построить минимальный пример:
TRAP_EXCEPTION
(
std::map<MyType, bool> Map;
)
catch(MyException& e)
{
}
Это дает следующие ошибки … как я могу это исправить (в идеале в макросе)?
> error C2143: syntax error : missing '>' before '}'
> error C2976: 'std::map' : too few template arguments
> error C2143: syntax error : missing ';' before '}'
Макросы не понимают параметров шаблона (точнее, угловых скобок), они просто видят ,
и думаю, что вы предоставили макросу два разных параметра. Вам необходимо добавить круглые скобки:
TRAP_EXCEPTION
(
(std::map<MyType, bool> Map;)
)
и макрос должен быть изменен:
#define UNWRAP(...) __VA_ARGS__
#define TRAP_EXCEPTION(statement) \
try \
{ \
try{UNWRAP statement} \
catch(Engine::Exception& e) \
{ \
throw MyException(e.message()); \
} \
}
Обратите внимание, что для этого потребуется всегда указывать дополнительную пару круглых скобок на стороне вызова.
В вашем случае (поскольку предполагается, что макрос принимает только один оператор), вы также можете использовать переменный макрос:
#define TRAP_EXCEPTION(...) \
try \
{ \
try{ __VA_ARGS__ } \
catch(Engine::Exception& e) \
{ \
throw MyException(e.message()); \
} \
}
что, вероятно, лучше, так как сторона вызова не меняется и
TRAP_EXCEPTION
(
std::map<MyType, bool> Map;
)
теперь будет работать правильно.
Препроцессор не распознает <
а также >
как скобки, так интерпретирует запятую как разделитель аргументов макроса. У вас возникла бы та же проблема, если бы оператор содержал запятую без скобок по любой другой причине (например, оператор запятой или запятые для разделения деклараторов).
Если вы действительно хотите злоупотреблять таким препроцессором, вы можете заставить его принять любое количество аргументов макроса:
#define TRAP_EXCEPTION(...) \
try \
{ \
try{__VA_ARGS__} \
catch(Engine::Exception& e) \
{ \
throw MyException(e.message()); \
} \
}
но я бы посоветовал вам не пытаться делать что-то умное с макросами.
Вместо __VA_ARGS__
Трюк, вы также можете использовать typedef перед макросом.
__VA_ARGS__
У трюка есть некоторые недостатки.
typedef std::map<MyType, bool> MyMap;
TRAP_EXCEPTION(
MyMap Map;
)