Здравствуйте, Аноним, Вы писали:

А>В статье по реализации делегатов на С++ надо было получить лексему через макросы:


А>
А>#define SUFFIX 5

А>#define COMBINE(a,b)       COMBINE1(a,b)
А>#define COMBINE1(a,b)      a##b

А>#define I_DELEGATE         COMBINE(IDelegate, SUFFIX)
А>#define C_STATIC_DELEGATE  COMBINE(CStaticDelegate, SUFFIX)
А>#define C_METHOD_DELEGATE  COMBINE(CMethodDelegate, SUFFIX)
А>#define C_DELEGATE         COMBINE(CDelegate, SUFFIX)
А>


А>К чему здесь COMBINE1? Я согласен, что в ином случае код не компилиться...

А>Вроде бы вот что происходит:
А>1) Строчка
А>
А>#define I_DELEGATE         COMBINE(IDelegate, SUFFIX)
А>

А>меняеться на
А>
А>#define I_DELEGATE         COMBINE(IDelegate, 5)
А>

А>2) Потом, когда в где-нибудь в коде встретиться I_DELEGATE (или др.), то выполниться макром
А>
А>#define COMBINE(a,b)       COMBINE1(a,b)
А>

А>но ведь если a — это I_DELEGATE и b — это 5, то вполне возможно написать и такое:
А>
А>#define COMBINE(a,b)       a##b
А>


А>Но я уверен, что заюлуждаюсь, т.к. это неправельно... Зачем все-таки нужен этот промежуточный макрос?


Читай 16.3.1/1. Если некоторые вхождения некоторых параметров макроса являются операндами операторов '##' или '#', то внутри этих вхождений не производится раскрытие макросов (которые могут там содержаться). Предположим, макрос 'COMBINE' объявлен вот так

#define COMBINE(a, b) a b a##b


и пытаемся применить этот макрос со следующими аргументами

#define ARG1 10
#define ARG2 20

COMBINE(ARG1, ARG2)


При выполнении макроподстановки параметров 'a' и 'b' макроса 'COMBINE' препроцессор позаботится о том, чтобы выполнить раскрытие макросов, содержащихся в параметрах 'a' и 'b', только в первых вхождениях этих параметров, и 'a b' будет заменено на '10 20'. А вот для вторых вхождений такого раскрытия делаться не будет, т.к. эти вхождения являются аргументами оператора '##', и 'a##b' будет заменено на 'ARG1ARG2'. Финальный результат будет таким: '10 20 ARG1ARG2'. В большинстве случаев это не то, что нужно.

Чтобы избежать вышеописанной проблемы применние оператора '##' выносят из основного макроса путем введения промежуточного макроса

#define COMBINE1(a, b) a##b
#define COMBINE(a, b) a b COMBINE1(a,b)


Теерь при выполнении макроподстановки макроса 'COMBINE' все параметры будут полностью раскрыты, т.к. ни один параметр не соседствует с оператором '##'. 'COMBINE(ARG1, ARG2)' заменится на '10 20 COMBINE1(10,20)'. Далее произойдет раскрытие макроса 'COMBINE1' и финальный результат будет иметь вид '10 20 1020'.

Вот поэтому в твоем случае и применен двухуровневый макрос.
Автор: Андрей Тарасевич    Оценить