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