Читать «Справочное руководство по 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 Повторный просмотр и дальнейшие подстановки

После того, как в строке замены произошла подстановка всех параметров макровызова, получившаяся строка просматривается повторно для обнаружения дополнительных макроопределений. Если в процессе повторных просмотров строки замены найдено имя макроопределения, то подстановка все же не происходит.