将 JSON 日志记录宏转换为模板函数...代码中需要的参数名称

发布于 2024-10-20 12:15:12 字数 1875 浏览 2 评论 0原文

不久前,我被分配了更新一个非常旧的项目的任务。我要做的第一件事是扩展现有代码以合并新功能。作为此过程的一部分,我修改了现有宏以打印传入消息的 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 如下所示:

“事件时间”:1299239194, “身份证”:1234567, “节点ID”:3

等...

显然我已经很好地注释了这些宏,但我希望为了其他人查看代码,有一种很好的方法可以使用模板实现相同的结果。我不得不说,这些宏确实使向消息记录器添加新事件变得非常容易。

基本上我如何使用模板执行“#X”和##X?

任何指示将不胜感激。

谢谢!

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 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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

情仇皆在手 2024-10-27 12:15:12

有些事情如果没有宏就无法完成,对于某些特定的上下文,宏就是解决方案。我将保留宏原样,然后继续执行下一个任务。

好吧,我实际上会尝试改进一下宏。通常建议不要在宏内部使用 ;,并且对于包含多个语句的宏,将它们包装在 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 ...

类似地,

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

即使它看起来足够正确,也会对编译器产生大量无意义的结果随意的眼睛。

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.

靖瑶 2024-10-27 12:15:12

我认为在很多情况下最好使用外部代码生成器...从一个很好的中性定义开始,很容易生成 C++、Javascript 等来处理您的数据。

C++ 模板非常原始,并且缺乏结构/类自省。通过玩一些技巧,您可以执行 if 和循环(哇!多么伟大的成就),但许多有用的技术却遥不可及。此外,一旦您的模板欺骗工作变得难以调试,在出现第一个错误时,程序员会让您看到一个又一个胡言乱语的屏幕,而不是清晰的错误消息。

另一方面,你有 C 预处理器,它在进行任何实际处理方面非常弱,并且只比正则表达式搜索/替换多一点(也少一点)。

为什么要坚持使用糟糕的工具,而不是仅仅实现一个单独的代码生成阶段(可以轻松地集成到 make 过程中),在其中您可以使用您选择的严肃语言来轻松进行处理和文本操作?
编写一个中性的易于解析的文件,然后使用 Python 程序生成 C++ 结构声明、序列化代码以及相应的 javascript 是多么容易?

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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文