开发者

Conversion of JSON logging macros to template functions... parameter names needed in code

I was assigned the task of updating a very old project a while back. The first thing I had to do was to expand the existing code开发者_JAVA百科 to incorporate a new feature. As part of this I modified existing macros to print JSON representations of incoming messages (over CORBA, into C++ structs). I then incorporated boost program_options and a new logger and now I want to modernise the macros.

The problem is that I have no idea how to implement what I did with the macros with templates. The key problem is that I use the name of the parameters to the macros to access the fields of the struct:

//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();

And it is used like this:

//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);
}

and this results in JSON like this:

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

etc...

Obviously I have commented these macros fairly well, but I am hoping that for the sake of anyone else looking at the code that there is a nice way to achieve the same result with templates. I have to say the macros do make it very easy to add new events to the message logger.

Basically how do I do "#X" and ##X with templates?

Any pointers would be appreciated.

Thanks!


There are some things that you cannot really do without macros, and for some specific contexts macros are the solution. I would just leave the macros as they are and move on to the next task.

Well, I would actually try to improve a bit the macros. It is usually recommended not to use ; inside macros, and with macros that contain more than a single statement wrap them in do {} while(0) loops:

#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)

This might help avoid small mistakes that would otherwise be hard to fix, as, for example uses of the macros with 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 ...

Similarly

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

would expand to a whole lot of non-sense for the compiler even if it looks correct enough to the casual eye.


I think that in many cases it's better to use an external code generator... starting from a nice neutral definition it's easy to generate C++, Javascript and whatnot to handle your data.

C++ templates are quite primitive and structure/class introspection is just absent. By playing some tricks you can be able to do ifs and loops (wow! what an accomplishment) but a lot of useful techniques are just out of reach. Also once you get your hard to debug template trickery working, at the first error the programmer makes you get screens and screens of babbling nonsense instead of a clear error message.

On the other side you have the C preprocessor, that is horribly weak at doing any real processing and is just a little more (and also less) than a regexp search/replace.

Why clinging to poor tools instead of just implementing a separate code generation phase (that can easily be integrated in the make process) where you can use a serious language of your choice able to do both processing and text manipulation easily? How easy would be to write a neutral easy-to-parse file and then using for example a Python program to generate the C++ struct declarations, the serialization code and also the javascript counterpart for that?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜