c++ - 根据 C++ 标准的语法解析数字文字的不一致

标签 c++ syntax c-preprocessor language-lawyer user-defined-literals

通读 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 进行词法分析,但随后无法回滚并应用语法规则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]
    }

这是对标准的正确解读吗?如果是这样,编译器应该处理这种可以说是罕见的极端情况是否合理?

最佳答案

您已成为 maximal munch rule 的受害者它使词法分析器采用尽可能多的字符来形成有效的标记。

这在 [lex.pptoken]p3 部分中有介绍上面写着(强调我的):

Otherwise, the next preprocessing token is the longest sequence of characters that could constitute a preprocessing token, even if that would cause further lexical analysis to fail, except that a header-name ([lex.header]) is only formed within a #include directive.

并包括几个例子:

[ Example:

#define R "x"
const char* s = R"y";           // ill-formed raw string, not "x" "y"

— end example ]

4 [ Example: The program fragment 0xe+foo is parsed as a preprocessing number token (one that is not a valid floating or integer literal token), even though a parse as three preprocessing tokens 0xe, +, and foo might produce a valid expression (for example, if foo were a macro defined as 1). Similarly, the program fragment 1E1 is parsed as a preprocessing number (one that is a valid floating literal token), whether or not E is a macro name. — end example ]

5[ Example: The program fragment x+++++y is parsed as x ++ ++ + y, which, if x and y have integral types, violates a constraint on increment operators, even though the parse x ++ + ++ y might yield a correct expression. — end example  ]

此规则适用于其他几个众所周知的案例,例如 a+++++btokens >= 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 符号 的产生,这就是这个案例的障碍。另一方面,如果您像第二个示例一样使用 d ,则不会遇到此问题( see it live on godbolt )。

此外,添加间距也可以解决您的问题,因为您将不再受制于最大咀嚼 (see it live on godbolt):

123_e + 1

关于c++ - 根据 C++ 标准的语法解析数字文字的不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53723392/

相关文章:

haskell - 如何为名称中包含非字母字符的库定义 MIN_VERSION_𝑙𝑖𝑏 宏?

c++ - 如何将 .c 和 .h 文件存储在包含路径中,与当前项目的源代码分开

C++ 管道和 fork

c++ - 在qt/linux中如何获取ip地址?

c++ - CUDA 编译器 (nvcc) 宏

c++ - Visual Studio 在命令行中定义预处理器指令

c++ - 无法打开包含文件 - 'gtest.h' - 没有这样的文件或目录

JavaScript 对象声明语法——变量名作为属性

mysql - mysql语法错误

求助MySQL FOREIGN KEY