利用宏方便地书写raw string literals

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用宏方便地书写raw string literals相关的知识,希望对你有一定的参考价值。

以前一直没用过标准库的regex,今天写一个hlsl的解析工具的时候用了一下,发现用字符串字面值写regular expression的时候非常不方便,特别是每个“\”字符都要被识别为转义,只能写成“\\”。比如,一系列空白字符加一个数字要写成这样:

std::regex reg("\\s*\\d");

这样一来,稍微一复杂的regular expression就完全没法看了。理所当然地,可以用raw string literal来解决这个问题。C++11中raw string literal的写法是这样的:

R"delimiter(string)delimiter"

其中delimiter是用来标识字符串的边界的。比方说——

std::cout << R"__("minecraft")__"

输出的结果就是"minecraft",注意输出的结果是有引号的。

用raw string literal的时候我就觉得,能不能把它搞得更直观一点,比如上面那个regular expression能不能写成

#define RAW_STR(str) something...
std::regex reg(RAW_STR(\s*\d));

于是我试着写了一个

#define RAW_STR(str, delimiter) R##"##delimiter##(##str##)##delimiter##"

结果发现##delimiter##(##str##)##delimiter##直接被两边的引号界定为了字符串字面值,str和delimiter作为宏参数根本没被展开出来。于是加了一层宏——

#define __ADD_QUOT(s) #s

专门用来添加引号。这时候又想起在有##或#的时候宏参数不会被展开,所以加了个中间层来展开参数:

#define __ADD_QUOT(s) __ADD_QUOT_AUX(s)
#define __ADD_QUOT_AUX(s) #s

就这样来来回回加了几个中间层,最后就变成了这样:

#define RAW_STR(str) \
    __RAW_STR_AUX_ADD_R(__RAW_STR_AUX_MAKE_STR(__RAW_STR_AUX_CAT(str)))
#define __RAW_STR_AUX_ADD_R(str) __RAW_STR_AUX_ADD_R1(str)
#define __RAW_STR_AUX_ADD_R1(str) R##str
#define __RAW_STR_AUX_MAKE_STR(cont) __RAW_STR_AUX_MAKE_STR1(cont)
#define __RAW_STR_AUX_MAKE_STR1(cont) #cont
#define __RAW_STR_AUX_CAT(str) __RAW_STR_AUX_CAT1(str)
#define __RAW_STR_AUX_CAT1(str) _____##(##str##)##_____

这里我用四个下划线作为delimiter,一般来说够用了。然后试了一下,还算能用。但是有个毛病没有解决:字面值的两端如果有“,”字符,会被预处理器当做宏参数的分隔符,而非宏参本身的一部分,导致不正确的结果。在写regular expression的时候,把这样的特殊字符用圆括号包起来就行了(反正对语义没有影响),比如

std::regex reg(RAW_STR(minecraft(,)));

当然,这个问题也许有更好的解决方法,以后再慢慢考虑。严格来说,这一堆宏在理论和工程上都没有什么用,就当自己寒假玩一玩了。

以上是关于利用宏方便地书写raw string literals的主要内容,如果未能解决你的问题,请参考以下文章

Litera同意收购领先的机器学习合同分析公司Kira Systems

C语言,宏表达式的书写格式,不调用变量数值交换

C语言中宏的运用------利用宏技术可以简化对某结构体变量的访问

我的OpenGL学习进阶之旅 C++ 长行字符串多行书写的方法以及如何书写正确的OpenGL Shader着色器代码

书写makefile的注意点

急求KRUSKAL算法求最小生成树过程演示