C++ 根据C++;标准&x27;语法

C++ 根据C++;标准&x27;语法,c++,syntax,c-preprocessor,language-lawyer,user-defined-literals,C++,Syntax,C Preprocessor,Language Lawyer,User Defined Literals,通过阅读C++17标准,在我看来,预处理器处理的pp number与数字文本(例如用户定义的整数文本)之间存在不一致,因为它们被定义为由“上层”语言处理 例如,根据预处理器语法,以下内容被正确解析为pp编号: 123_e+1 但是放在符合C++11的代码片段的上下文中 int operator"" _e(unsigned long long) { return 0; } int test() { return 123_e+1; } 当前的Clang或GCC

通过阅读C++17标准,在我看来,预处理器处理的
pp number
与数字文本(例如
用户定义的整数文本
)之间存在不一致,因为它们被定义为由“上层”语言处理

例如,根据预处理器语法,以下内容被正确解析为
pp编号

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'
其中未找到
运算符“”\u e(…)
,尝试定义
运算符“”\u e+1(…)
将无效

这似乎是因为编译器首先将标记解析为
pp编号
,但在解析最终表达式时,无法回滚并应用
用户定义整数文本的语法规则

相比之下,以下代码编译得很好:

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]
    }

这是标准的正确读数吗?如果是这样的话,编译器应该处理这种可能很少见的特殊情况,这合理吗?

您已经成为了词法分析器使用尽可能多的字符来形成有效标记的问题的受害者

这在第节(强调我的)中有说明:

否则,下一个预处理标记是可能构成预处理标记的最长字符序列,,即使这会导致进一步的词法分析失败,但标题名([lex.header])仅在#include指令中形成

并包括几个示例:

[ 例如:

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

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

五,[ 示例:程序片段x+++y被解析为x+++++y, 如果x和y具有整数类型,则会违反 增量运算符,即使解析x+++y可能会产生 正确的表达- 结束示例 ]

此规则适用于其他几个众所周知的情况,例如和

作为参考,pp标记语法如下所示:

注意
e符号
production,这就是本例的障碍所在。如果另一方面,您像第二个示例一样使用
d
,则不会遇到此问题()

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


注意,MSVC编译这两种情况都很好。在中不允许使用下划线!因此解析
123_e+1
as
pp number
是错误的…@Aconcagua-实际上
pp number
lexes
标识符非数字
非数字
包括下划线。这不是一个答案,因为我不能100%确定这对于C++17是正确的,但C中也存在类似的情况,解释是标准实际上要求它是一个错误:每个pp标记都要转换为一个且仅一个phase-7标记,编译器不允许“回滚”正如你所说的,“安迪格哦,你似乎是对的,抱歉,但是<代码> +/CODE >没有被覆盖。有趣的是,P/P被包括在内,但是0X前缀也不是……因为你再次打动我,我多年来没有仔细阅读C++标准,特别是我不知道是否有特殊的用户定义文字规则。如果您还考虑了5.1.1.2p1#7的通常解释“每个预处理令牌都转换为一个令牌”,即一个且只有一个令牌——编译器也不应该将单个pp令牌拆分为两个阶段7令牌,即使这会导致有效的解析。(第7阶段标记上的最大munch将产生示例4中的
0xe+foo
,因为
0xe
是一个整数文本标记,并且整数文本的产生在该点不允许
+
)感谢您的回答和标准中的示例。@zwol仅按照解析器规则,我认为
0xe+foo
需要作为一个标记被接受-据我所知(和所学…),将标记解释为整数或FP文本是在稍后阶段完成的?@Aconcagua我的意思是这就是全部问题。
0xe+foo
是一个预处理标记。编写标准可以指定在预处理后重复词法分析,在这种情况下,pp标记
0xe+foo
将变为三个阶段7到KEN,整数文字>代码> 0x3< /代码>,操作符<代码> +/>代码>标识符>代码> Foo<代码>。C标准不是这样写的,而是要求<代码> 0xe+Foo>代码>转换为单相7令牌,并且没有与之匹配的词汇生成,因此这是语法错误。我相信,但我不确定100%,C++。标准也是如此。
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 .  
123_e + 1