Преобразование макросов регистрации JSON в шаблонные функции ... имена параметров, необходимые в коде - PullRequest
0 голосов
/ 04 марта 2011

Некоторое время назад мне было поручено обновить очень старый проект. Первое, что мне нужно было сделать, - это расширить существующий код, чтобы включить новую функцию. В рамках этого я модифицировал существующие макросы для печати представлений JSON входящих сообщений (через CORBA, в структуры C ++). Затем я добавил boost program_options и новый регистратор, и теперь я хочу модернизировать макросы.

Проблема в том, что я понятия не имею, как реализовать то, что я делал с макросами с помощью шаблонов. Основная проблема заключается в том, что я использую имя параметров в макросах для доступа к полям структуры:

//Defines the string that precedes the variable name in a JSON name-value pair (newline,indent,")
#define JSON_PRE_VNAME      _T("%s,\n\t\t\t\t\"")
//Defines the string that follows the variable name in a JSON name-value pair (":) preceding the value
#define JSON_SEP            _T("\":")
#define printHex(Y,X)       _tprintf(_T("%02X"), (unsigned char)##Y->##X );

// ******** MACRO **********
// printParam (StructureFieldName=X, ParamType=Y)
// prints out a json key value pair.
// e.g. printParam(AgentId, %s) will print "AgentId":"3910"
// e.g. printParam(TempAgent, %d) will print "TempAgent":1

#define printParam(X,Y)         if(strcmp(#Y,"%s")==0){\
                                    _byteCount += _stprintf(_logBuf,JSON_PRE_VNAME _T(#X) JSON_SEP _T("\"%s\""),_logBuf,myEvent->##X);\
                                }else{\
                                    _byteCount += _stprintf(_logBuf,JSON_PRE_VNAME _T(#X) JSON_SEP _T(#Y),_logBuf,myEvent->##X);\
                                }\
                                printBufToLog();

И это используется так:

//CORBA EVENT AS STRUCT "event"
else if(event.type == NI_eventSendInformationToHost ){
    evSendInformationToHost *myEvent;
    event.data >>= myEvent;  //demarshall
    printParam(EventTime,%d);
    printParam(Id,%d);
    printParam(NodeId,%d);
}

и это приводит к JSON так:

"EventTime": 1299239194, "Id": 1234567, "NodeId": 3

и т.д ...

Очевидно, что я достаточно хорошо прокомментировал эти макросы, но я надеюсь, что для всех, кто смотрит на код, есть хороший способ добиться того же результата с помощью шаблонов. Я должен сказать, что с помощью макросов очень легко добавлять новые события в регистратор сообщений.

Как мне сделать "#X" и ## X с шаблонами?

Любые указатели приветствуются.

Спасибо!

Ответы [ 2 ]

2 голосов
/ 04 марта 2011

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

Ну, я бы на самом деле попытался немного улучшить макросы. Обычно рекомендуется не использовать ; внутри макросов, а с макросами, которые содержат более одного оператора, оберните их в do {} while(0) циклы:

#define printHex(Y,X)       _tprintf(_T("%02X"), (unsigned char)##Y->##X ) 
//                                                               remove ; ^

// add do while here:
#define printParam(X,Y)         do { if(strcmp(#Y,"%s")==0){\
                                    _byteCount += _stprintf(_logBuf,JSON_PRE_VNAME _T(#X) JSON_SEP _T("\"%s\""),_logBuf,myEvent->##X);\
                                }else{\
                                    _byteCount += _stprintf(_logBuf,JSON_PRE_VNAME _T(#X) JSON_SEP _T(#Y),_logBuf,myEvent->##X);\
                                }\
                                printBufToLog();\
                                } while (false)

Это может помочь избежать мелких ошибок, которые иначе было бы трудно исправить, как, например, использование макросов с if:

if (condition) printHex(a,b);
else printHex(c,d);

// looks good, but would originally expand to a syntax error:
if (condition) _tprintf(_T("%02X"), (unsigned char)##Y->##X );;
else ...

Аналогично * * 1014

if (condition) printParam(a,b);
else ... 

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

1 голос
/ 04 марта 2011

Я думаю, что во многих случаях лучше использовать внешний генератор кода ... начиная с хорошего нейтрального определения, легко генерировать C ++, Javascript и еще много чего для обработки ваших данных.

Шаблоны C ++ довольно примитивны, а самоанализ структуры / класса просто отсутствует. Играя в некоторые трюки, вы можете делать if и циклы (вау! Какое достижение), но многие полезные техники просто недосягаемы. Кроме того, как только вы получаете трудную для отладки хитрость шаблона, при первой ошибке программист заставляет вас получать экраны и экраны бессмысленной чепухи вместо четкого сообщения об ошибке.

С другой стороны у вас есть препроцессор C, который ужасно слаб при выполнении любой реальной обработки и лишь немного больше (а также меньше), чем поиск / замена регулярных выражений.

Зачем цепляться за плохие инструменты вместо того, чтобы просто реализовывать отдельную фазу генерации кода (которую можно легко интегрировать в процесс создания), где вы можете использовать серьезный язык по вашему выбору, способный легко выполнять как обработку, так и обработку текста? Насколько легко было бы написать нейтральный файл, который легко анализировать, а затем использовать, например, программу Python для генерации объявлений структуры C ++, кода сериализации, а также аналога javascript для этого?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...