通读C ++ 17标准,在我看来,由预处理器处理的 pp-number
与数字文字(例如 user-defined-integer-literal
,因为它们被定义为由“上层”语言处理。
例如,根据预处理程序语法,以下内容正确地解析为 pp-number
:
123_e+1
但是放置在C ++ 11兼容代码片段的上下文中,
int operator"" _e(unsigned long long)
{ return 0; }
int test()
{
return 123_e+1;
}
当前的Clang或GCC编译器(我尚未测试其他编译器)将返回类似于以下的错误:
unable to find numeric literal operator 'operator""_e+1'
未找到operator"" _e(...)
且试图定义operator"" _e+1(...)
的情况将是无效的。
这似乎是由于编译器首先将令牌作为 pp-number
进行词法分析,然后又无法回滚并为 {{ 1}} 解析最终表达式时。
相比之下,以下代码可以很好地编译:
user-defined-integer-literal
这是对标准的正确阅读吗?如果是这样,编译器应该处理这种可能很少见的特殊情况是否合理?
答案 0 :(得分:3)
您已经成为maximal munch rule的牺牲品,该词法分析器使用尽可能多的字符来构成有效的令牌。
第[lex.pptoken]p3节对此进行了介绍,该段内容为(强调我的):
否则,下一个预处理标记是可能构成预处理标记的最长字符序列,即使会导致进一步的词法分析失败,除了标题名称([lex。标头])仅在#include指令内形成。
并包含几个示例:
[示例:
#define R "x" const char* s = R"y"; // ill-formed raw string, not "x" "y"
-示例]
4 [示例:程序片段 0xe + foo被解析 作为预处理数字令牌(不是有效的浮动或 整数文字标记),即使将其解析为三个预处理 标记0xe,+和foo可能会产生有效的表达式(例如, 如果foo是定义为1的宏)。同样,程序片段1E1 被解析为预处理编号(一个有效的浮点数 文字标记),无论E是否为宏名。 —示例]
5 [示例:程序片段x +++++ y解析为x ++ ++ + y, 如果x和y具有整数类型,则违反 即使分析x ++ + ++ y可能会产生一个增量运算符 正确的表达。 —示例example]
此规则在a+++++b和tokens >= which required a fix to allow等其他一些知名案例中也会生效。
pp-token 语法如下:
pp-number: digit . digit pp-number digit pp-number identifier-nondigit pp-number ' digit pp-number ' nondigit pp-number e sign pp-number E sign pp-number p sign pp-number P sign pp-number .
注意e sign
的产生,这就是这种情况的困扰。另一方面,如果您像第二个示例一样使用d
,则不会点击该(see it live on godbolt)。
添加间距也可以解决您的问题,因为您将不再受到最大的浪费(see it live on godbolt):
123_e + 1