понедельник, 12 октября 2009 г.

Извращенные макросы

Довожу Parammix до следующего билда и появилась забавная идея – каким нибудь чудом перегрузить макрос регистрации параметров с возможностью не указывать дефолтные инициализационные значения (например для векторов – конструкции вида REG_PARAMETER(boomer,std::vector<int>()) очень портят настроение.

Итак, покапавшись в разрозненной и очень скудной зарубежной информации по трюкам с макросами прояснилось следующее:

1) переменное количество аргументов достигается с помощью

#define REG_PARAMETER(name,...)       MAKE_PARAMETER(name,__VA_ARGS__)  //для msc

#define REG_PARAMETER(name,args...) MAKE_PARAMETERS(name,args)               //для gcc

2) поменять содержимое макроса можно с помощью игры с комментариями, например такая конструкция

#define FOO(a,...) /**__VA_ARGS__/a/__VA_ARGS__**/

будет выдавать a если нет дополнительных параметров. Разумеется данный макрос неверен, поэтому немного изменим его, для этого обратим внимание на:

3) разграничивать комментарии очень удобно с помощью

#define RR(name) name

 

Перепишем макрос FOO :

#define FOO(a,...) RR(/RR(**__VA_ARGS__)/RR(a)/RR(__VA_ARGS__**)/)

вот так намного лучше, превращать макрос в пустоту при наличии аргументов мы умеем.

 

Теперь задачка посложнее – обратная. Т.е. без аргументов должна оставаться пустая строка, а при наличии аргумента производиться определенное действие – в моем случае инициализация переменной дефолтным значением.

Ход мыслей

- надо выполнить код name=def; при наличии аргумента def

- аргумент def послужит переключалкой

- воображение рисует такую конструкцию /def*/name=def;/**/ – вроде все логично, без аргумента def строка обращается в комментарий, с аргументом – искомую строка становится доступной,  концевой буфер предохраняет нас в обоих случаях. Проблема – не скрывается сам аргумент в –переключателе-.

- приходит мысль модифицировать –переключатель- следующим образом /**def//def*/- данная конструкция скроект аргумент переключатель, осталось собрать все воедино и не забывать про пункт 3 - обратите внимание на двойную косую, может случайно получится комментарий, так что лучше перепишем ее как /RR()/, так безопасней.

- получается такая штука

#define  GOO(a,def) RR(/RR(**def)/RR( )/RR(def*)/RR(name=def;)/RR(**)/)
#define  FOO(a,…) GOO(a,__VA_ARGS__)

Вот такое чудо. Мне пригодилось – надеюсь и вам пригодится. Очень хочу услышать более красивые решения.