Подтвердить что ты не робот

Почему заменители аргументов не заменяются при повторном сканировании?

Рассмотрим следующие макроопределения и вызовы:

#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 в цитируемых разделах.

4b9b3361

Ответ 1

Я считаю, что вы процитировали ключевой параграф, вы просто остановились слишком рано. 16.3.4/2 (основное внимание):

Если имя заменяемого макроса найдено во время этого сканирования список замены (не включая остальные исходные файлы токены предварительной обработки), это не заменены. Кроме того, если какой-либо вложенный встреча замещений имя заменяемого макроса, он не заменяется. Эти неприменимые маркеры предварительной обработки макросов не являются дольше доступны для дальнейшего замена, даже если они позже (re) в контекстах, в которых маркер предварительной обработки макросов в противном случае были заменены.

Итак, когда x заменяется на x[0] во время замены параметра y, он полностью заменяется макросом, что означает, что он повторно сканируется в этой точке, а x попадает в правило рекурсии. Это означает, что x in x[0] больше не подходит для дальнейшей замены, в том числе при повторном сканировании частично расширенного результата y(x).