Рассмотрим следующие макроопределения и вызовы:
#define x x[0]
#define y(arg) arg
y(x)
Этот вызов расширяется до x[0] (тестируется на Visual С++ 2010, g++ 4.1, mcpp 2.7.2 и Wave).
Почему? В частности, почему он не расширяется до x[0][0]?
Во время замены макроса
Параметр в списке замены... заменяется соответствующим аргументом после того, как все макросы, содержащиеся в нем, были расширены. Перед заменой каждый токер предварительной обработки аргументов полностью заменяется макросом (С++ 03 §16.3.1/1).
Оценивая вызов макроса, мы делаем следующие шаги:
- Функциональный макрос
yвызывается с помощьюxв качестве аргумента для параметраarg -
xв аргументе заменяется макросом, становясьx[0] -
argв списке замещения заменяется заменяемым макросом значением аргумента,x[0]
Список заметок после подстановки всех параметров x[0].
После того, как все параметры в списке замещения были заменены, результирующая последовательность токенов препроцессора будет rescanned... для замены более имени макроса (С++ 03 §16.3.4/1).
Если имя заменяемого макроса найдено во время сканирования списка замены... оно не заменяется. Кроме того, если какие-либо вложенные замены встречаются с именем заменяемого макроса, он не заменяется (С++ 03 §16.3.4/2).
Заменен список замены x[0] (обратите внимание, что имя заменяемого макроса y):
-
xидентифицируется как объект-подобный вызов макроса -
xзаменяется наx[0]
Замена останавливается на этом этапе из-за правила в §16.3.4/2, предотвращающего рекурсию. Список замены после повторного сканирования - x[0][0].
Я явно неправильно истолковал что-то, потому что все препроцессоры, которые я тестировал, говорят, что я ошибаюсь. Кроме того, этот пример является куском большего примера в С++ 0x FCD (в §16.3.5/5), и он также говорит, что ожидаемая замена x[0].
Почему x не заменяется во время повторного сканирования?
C99 и С++ 0x фактически имеют ту же формулировку, что и С++ 03 в цитируемых разделах.