Jan*_*dec 2 c++ clang language-lawyer c-preprocessor c++03
为了简化在C++中编写SQL查询,我使用宏
#define SQL(...) #__VA_ARGS__
Run Code Online (Sandbox Code Playgroud)
它工作正常,除非出现空字符串文字(类似于
SQL(select * from foo where bar = '')
Run Code Online (Sandbox Code Playgroud)
),clang(没有其他编译器)发出警告
warning: empty character constant [-Winvalid-pp-token]
Run Code Online (Sandbox Code Playgroud)
我正在做一个严重的黑客(我仍然保持,因为它允许多行sql语句可读)违反标准或在这里过于关键(字符文字没有出现在预处理器指令中)?
编辑:忘记提及并非所有平台都支持C++ 11,因此我们不能使用原始字符串文字.我们可能会坚持使用VisualC++ 9.0多年,而Gcc 4.6-somesnapshot可能更少,但仍然是几年.黑客攻击也早于C++ 11.
你正在做的是一个严重的黑客攻击,如果你正在使用Clang(和其他现代编译器)进行编译但不需要支持较旧的编译器,那么有一种更简单的方法:原始字符串文字.
std::string query = R"sql(
select * from foo where bar = ''
)sql";
Run Code Online (Sandbox Code Playgroud)
如果您愿意,这甚至允许您在查询中嵌入引号和反斜杠而不转义.
作为参考,自Clang 3.0,GCC 4.5和Visual Studio 2013以来,支持原始字符串文字.
从语言律师的角度来看,Clang慷慨地允许你的代码编译.它无效.C++ 14 2.2表示在阶段3(宏替换发生在阶段4中),源文件被分解为预处理令牌和空白序列.
2.5列出了预处理 - 令牌语法生成.那里只有一个以单引号开头的选项,即字符文字.字符文字在2.14.3中定义为
character-literal:
' c-char-sequence '
<prefixed versions>
c-char-sequence:
c-char
c-char-sequence c-char
c-char:
any member of the source character set except
the single-quote ' , backslash \, or new-line character
escape-sequence
universal-character-name
Run Code Online (Sandbox Code Playgroud)
请注意,c-char-sequence由至少一个c-char组成,而c-char不能是单引号.因此,C++中的语法生成不匹配''.此序列不能出现在更大的事物之外的符合程序中(如字符串文字).
宏进程在字符级别上不起作用,毕竟它在令牌级别上工作.一切都需要先被标记化.