Читать «Справочное руководство по C++» онлайн - страница 91
Бьярн Страустрап
После идентификации параметров для функционального макроопределения происходит подстановка фактических параметров. После выполнения подстановок в параметре (если они были) этот параметр в строке замены замещается фактическим параметром из макровызова (§R.16.3.3); исключения составляют случаи, когда параметру предшествует лексема # (§R.16.3.1), или с ним соседствует лексема ## (§R.16.3.2).
Приведем пример. Пусть есть макроопределения
#define index_mask 0XFF00
#define extract(word,mask) word & mask
Тогда макровызов
index = extract(packed_data,index_mask);
после подстановки примет вид
index = packed_data & 0XFF00;
Для обоих видов макроопределений строка замены проверяется на наличие других макроопределений (§R.16.3.3).
R.16.3.1 Операция #
Если непосредственно перед параметром в строке замены идет лексема #, то при подстановке параметр и операция # будут заменены на строку литералов, содержащую имя соответствующего параметра макровызова. В символьной константе или строке литералов, входящих в параметр, перед каждым вхождением \ или " вставляется символ \.
Например, если есть макроопределения
#define path(logid,cmd) "/usr/" #logid "/bin/" #cmd
то макровызов
char* mytool=path(joe,readmail);
приведет к такому результату:
char* mytool="/usr/" "joe" "/bin/" "readmail";
После конкатенации соседних строк (§R.16.1) получим:
char* mytool="/usr/joe/bin/readmail";
R.16.3.2 Операция ##
Если в строке замены между двумя лексемами, одна из которых представляет параметр макроопределения, появляется операция ##, то сама операция ## и окружающие ее обобщенные пробелы удаляются. Таким образом, результат операции ## состоит в конкатенации.
Пусть есть макроопределение,
#define inherit(basenum) public Pubbase ## basenum, \
private Privbase ## basenum
тогда макровызов
class D: inherit(1) {};
приведет к такому результату:
class D: public Pubbase1, Privbase1 {};
Макроопределение, которое в строке замены соседствует с ##, не подлежит подстановке, однако, результат конкатенации может использоваться для подстановки. Приведем пример. Пусть есть определения:
#define concat(a) a ## ball
#define base B
#define baseball sport
Тогда макровызов
concat(base)
даст в результате
sport
а вовсе не
Bball
R.16.3.3 Повторный просмотр и дальнейшие подстановки
После того, как в строке замены произошла подстановка всех параметров макровызова, получившаяся строка просматривается повторно для обнаружения дополнительных макроопределений. Если в процессе повторных просмотров строки замены найдено имя макроопределения, то подстановка все же не происходит.