Стандарты программирования на С++. 101 правило и рекомендация | страница 36
— [Stroustrup00] §7.8
Основная проблема с макросами С++ заключается в том, что они выглядят гораздо привлекательнее, чем являются таковыми на самом деле. Макросы игнорируют области видимости, игнорируют прочие возможности и правила языка, и заменяют все символы, которые переопределяют при помощи директивы >#define
, до самого конца файла. Применение макросов внешне походит на имя или вызов функции, но не имеет с ними ничего общего. Макросы "негигиеничны", в том смысле, что они могут быть раскрыты неожиданно, причем превратиться в зависимости от контекста их использования в самые разные конструкции. Подстановка текста, выполняемая макросами, делает написание хотя бы в небольшой степени "приличного" макроса смесью искусства и черной магии.
Программисты, которые полагают, что тяжелее всего расшифровать ошибки, связанные с шаблонами, вероятно, просто никогда не имели дела с плохо написанными или неверно использованными макросами. Шаблоны являются частью системы типов С++, и тем самым позволяют компилятору куда лучше справляться с ними, чем с макросами, которые имеют мало общего с языком программирования. Хуже того, в отличие от шаблонов неверные макросы могут быть раскрыты в нечто, что в силу чистой случайности скомпилируется, не имея при этом никакого смысла. И наконец, ошибка в макросе обнаруживается только после того, как макрос раскрывается, а не при его определении.
Даже в тех редких случаях, где применение макросов оправданно (см. подраздел, посвященный исключениям), нельзя даже подумать о том, чтобы написать макрос, который является распространенным словом или аббревиатурой. Для всех макросов как можно скорее применяйте директиву >#undef
, всегда давая им необычные уродливые имена в верхнем регистре, избегая при этом размещения их в заголовочных файлах.
Пример. Передача инстанцирования шаблона макросу. Макросы понимают в достаточной мере только круглые и квадратные скобки. В С++, однако, определена новая конструкция с угловыми скобками, используемая в шаблонах. Макросы не могут корректно обработать эту ситуацию, так что вызов
>macro(Foo
макрос воспринимает так, будто ему переданы два аргумента, а именно >Foo
>doublе>
, в то время как в действительности эта конструкция представляет собой единый объект С++.
Макросы остаются единственно возможным решением для некоторых важных задач, таких как защита директивы >#include
(см. рекомендацию 24), использование директив