Ответ 1
Фактически, это зависит от вашей интерпретации языкового стандарта. Например, в mcpp, реализация препроцессора, которая строго соответствует тексту стандартного языка, вторая дает CAT(x, y);
, а также [дополнительные строки новой строки были удалены из результата]:
C:\dev>mcpp -W0 stubby.cpp
#line 1 "C:/dev/stubby.cpp"
CAT(x, y) ;
CAT(x, y) ;
C:\dev>
В спецификации языка С++ существует известная несогласованность (такая же несогласованность присутствует в спецификации C, хотя я не знаю, где список дефектов для C). В спецификации указано, что окончательный CAT(x, y)
не должен заменяться макросъемкой. Возможно, это было намерение заменить макросмену.
Чтобы процитировать связанный отчет о дефекте:
Еще в 1980 году несколько представителей WG14 поняли, что между "не заменяющей" формулировкой и попытками создания псевдокода существуют небольшие различия.
Решение комитета состояло в том, что никакие реалистичные программы "в дикой природе" не решаются в этой области, и попытка уменьшить неопределенности не стоит риска изменения статуса соответствия реализаций или программ.
Итак, почему мы получаем другое поведение для M(0)
, чем для N(0)
с наиболее распространенными реализациями препроцессора? При замене M
второй вызов CAT
состоит только из токенов, полученных в результате первого вызова CAT
:
M(0)
CAT(M_, 0)
CAT_I(M_, 0)
M_0
CAT(x, y)
Если вместо M_0
было заменено на CAT(M, 0)
, замена будет бесконечно возвращаться. Спецификация препроцессора явно запрещает эту "строго рекурсивную" замену путем остановки замены макроса, поэтому CAT(x, y)
не заменяется макросом.
Однако при замене N
второй вызов CAT
состоит только частично из токенов, полученных в результате первого вызова CAT
:
N(0)
CAT(N_, 0) ()
CAT_I(N_, 0) ()
N_0 ()
CAT(x, y)
CAT_I(x, y)
xy
Здесь второе обращение CAT
формируется частично из токенов, полученных в результате первого вызова CAT
и частично из других токенов, а именно ()
из списка замены N
. Замена не является строго рекурсивной и, следовательно, при замене второго вызова CAT
он не может дать бесконечную рекурсию.