调用伪析构函数以获取浮点常量的有效语法


9

考虑下面的演示程序。

#include <iostream>

int main()
{
    typedef float T;

    0.f.T::~T();
}

该程序由编译Microsoft Visual Studio Community 2019

但是clanggcc发出这样的错误

prog.cc:7:5: error: unable to find numeric literal operator 'operator""f.T'
    7 |     0.f.T::~T();
      |     ^~~~~

如果要像这样写表达式,( 0.f ).T::~T()则所有三个编译器都将编译该程序。

因此出现一个问题:此记录在0.f.T::~T()语法上是否有效?如果没有,那么什么语法规则就被打破了?


1
在之间放置一个空格0.f.T会使GCC和Clang都接受这一点...
chris

1
以及(0.f).T::~T();
cigien

一个简单的float f = 1.0f.t;将产生有关数字文字的错误。
1201ProgramAlarm

A float内置类型,它没有析构函数供您调用。您甚至在手动调用析构函数在做什么?在新的安置区域之外,这应该是一个很大的禁忌。
Jesper Juhl,

@JesparJuhl它不是析构函数而是伪析构函数,我只是知道它存在。标签信息有一个示例(它也有一个不合理的调用析构函数btw的调用)
idclev 463035818

Answers:


3

数字标记的解析非常粗糙,并且允许许多实际上不是有效数字的事物。在C ++ 98中,在[lex.ppnumber]中找到的“预处理编号”的语法是

pp-number:
    digit
    . digit
    pp-number digit
    pp-number nondigit
    pp-number e sign
    pp-number E sign
    pp-number .

在这里,“非数字”是可以在标识符中使用的任何字符,除了数字以外,“符号”是+或-。后来的标准将扩展定义,以允许使用单引号(C ++ 14)和格式为p-,p +,P-,P +的序列(C ++ 17)。

结果是,在该标准的任何版本中,都要求预处理数字以数字或以句点开头的数字开头,之后可以是数字,字母和句点的任意序列。使用最大munch规则,即使不是有效的数字令牌,0.f.T::~T();也需要将其标记为。0.f.T :: ~ T ( ) ;0.f.T

因此,该代码是不是语法上有效。


有趣的是,[lex.pptoken]中实际上有一个示例具有不错的相似性:eel.is/c++draft/lex.pptoken#5
chris

1

用户定义的文字后缀ud-suffix是一个标识符。一个标识符是字母(包括一些非ASCII字符),下划线和数字不以数字开头的序列。不包含句点字符。

因此,这是一个编译器错误,因为它将非标识符序列f.T视为标识符。

0.是一个分数常数,其可以接着任选的指数,则无论是UD-后缀(用于定义文字的用户)或浮点后缀(之一fFlL)。该f可被认为是UD-suffx为好,但由于它的另一个文本类型相匹配的应该是,而不是UDL。甲UD-后缀在语法作为标识符定义。


为什么将其解释为ud后缀?
弗拉德(Vlad)从莫斯科

@VladfromMoscow这0.是一个分数常数。后面可以加上ud后缀(用于用户定义的文字)(不包括指数填充)或浮点后缀(之一fFlL)。该f可被认为是UD-suffx为好,但由于它的另一个文本类型相匹配的应该是,而不是UDL。甲UD-后缀在语法作为定义标识符
1201ProgramAlarm

@ 1201ProgramAlarm:而f可以解释为ud-suffix, f.T而不应该因为.不能在标识符中出现。但这是...我会说编译器错误,但可以肯定它更复杂。
Jarod42
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.