根据C++ Standard的语法解析数字文字的不一致性

And*_*y G 12 c++ syntax language-lawyer user-defined-literals c-preprocessor

通过C++ 17标准阅读,在我看来,pp-number预处理器和数字文字处理之间存在不一致,例如user-defined-integer-literal,它们被定义为由"上层"语言处理.

例如,pp-number根据预处理器语法正确解析以下内容:

123_e+1
Run Code Online (Sandbox Code Playgroud)

但放在符合C++ 11的代码片段的上下文中,

int  operator"" _e(unsigned long long)
    { return 0; }

int test()
    {
    return 123_e+1;
    }
Run Code Online (Sandbox Code Playgroud)

目前的Clang或GCC编译器(我还没有测试过其他编译器)会返回类似这样的错误:

unable to find numeric literal operator 'operator""_e+1'
Run Code Online (Sandbox Code Playgroud)

在那里operator"" _e(...)没有找到,并试图定义operator"" _e+1(...)将是无效的.

似乎这是因为编译器将令牌作为pp-number第一个使用,但是user-defined-integer-literal在解析最终表达式时无法回滚并应用语法规则.

相比之下,以下代码编译正常:

int  operator"" _d(unsigned long long)
    { return 0; }

int test()
    {
    return 0x123_d+1;  // doesn't lex as a 'pp-number' because 'sign' can only follow [eEpP]
    }
Run Code Online (Sandbox Code Playgroud)

这是标准的正确读数吗?如果是这样,编译器应该处理这个,可以说是罕见的极端案例是否合理?

Sha*_*our 3

您已经成为最大咀嚼规则的受害者,该规则使词法分析器采用尽可能多的字符来形成有效的标记。

\n\n

[lex.pptoken]p3节对此进行了介绍(强调我的):

\n\n
\n

否则,下一个预处理标记是可以构成预处理标记的最长字符序列,即使这会导致进一步的词法分析失败,除非标头名称 ([lex.header]) 仅在 #include 内形成指示。

\n
\n\n

并包括几个例子:

\n\n
\n

[\xe2\x80\x89示例:

\n\n
#define R "x"\nconst char* s = R"y";           // ill-formed raw string, not "x" "y"\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\x80\x94\xe2\x80\x89结束示例\xe2\x80\x89]

\n\n

4 [\xe2\x80\x89示例:程序片段0xe+foo 被解析为预处理数字标记(不是有效的浮点或整数文字标记),即使解析为三个预处理标记0xe、+ 和 foo 可能会生成有效的表达式(例如,\n 如果 foo 是定义为 1 的宏)。类似地,程序片段 1E1\n 被解析为预处理数字(一个有效的浮点\n 文字标记),无论 E 是否是宏名称。\xe2\x80\x94\xe2\x80\x89结束示例]

\n\n

5[\xe2\x80\x89示例:程序片段 x+++++y 被解析为 x ++ ++ + y,\n 如果 x 和 y 具有整数类型,则违反\n 增量运算符的约束,即使解析 x ++ + ++ y 可能会产生正确的表达式。\xe2\x80\x94\xe2\x80\x89end 示例 \xe2\x80\x89]

\n
\n\n

此规则会影响其他几个众所周知的情况,例如a+++++b标记 >= ,需要修复才能允许.

\n\n

作为参考,pp-token语法如下:

\n\n
\n
pp-number:  \n  digit  \n  . digit  \n  pp-number digit  \n  pp-number identifier-nondigit \n  pp-number \' digit  \n  pp-number \' nondigit    \n  pp-number e sign  \n  pp-number E sign  \n  pp-number p sign  \n  pp-number P sign  \n  pp-number .  \n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

注意e sign生产,这就是这个案例的问题所在。另一方面,如果你d像第二个例子一样使用,你就不会碰到这个(在 godbolt 上看到它)。

\n\n

另外添加间距也可以解决您的问题,因为您将不再受到最大咀嚼的影响(请参阅 godbolt 上的直播):

\n\n
123_e + 1\n
Run Code Online (Sandbox Code Playgroud)\n


归档时间:

查看次数:

258 次

最近记录:

7 年,5 月 前