Gültige Syntax zum Aufrufen des Pseudo-Destruktors für eine schwebende Konstante

9

Betrachten Sie das folgende Demonstrationsprogramm.

#include <iostream>

int main()
{
    typedef float T;

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

Dieses Programm wird zusammengestellt von Microsoft Visual Studio Community 2019.

Aber clangund gccgeben Sie einen Fehler wie diesen aus

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

Wenn der Ausdruck wie ( 0.f ).T::~T()folgt geschrieben werden soll, kompilieren alle drei Compiler das Programm.

Es stellt sich also die Frage: Ist dieser Datensatz 0.f.T::~T()syntaktisch gültig? Und wenn nicht, welche syntaktische Regel ist dann gebrochen?

Vlad aus Moskau
quelle
1
Wenn Sie ein Leerzeichen zwischen 0.fund setzen, werden .TGCC und Clang dies akzeptieren ...
Chris
1
Sowie(0.f).T::~T();
cigien
Ein einfaches float f = 1.0f.t;wird den Fehler über das numerische Literal erzeugen.
1201ProgramAlarm
A floatist ein eingebauter Typ, es gibt keinen Destruktor, den Sie aufrufen können. Was machst du überhaupt, wenn du Destruktoren manuell aufrufst? Außerhalb von Neuland sollte dies ein großes Nein-Nein sein.
Jesper Juhl
@JesparJuhl Es ist kein Destruktor, sondern ein Pseudo-Destruktor. Ich habe gerade erfahren, dass es existiert. Die Tag-Informationen enthalten ein Beispiel (das übrigens auch einen nicht gerechtfertigten Aufruf des Destruktors enthält).
idclev 463035818

Antworten:

3

Das Parsen von numerischen Token ist ziemlich grob und erlaubt viele Dinge, die eigentlich keine gültigen Zahlen sind. In C ++ 98 lautet die Grammatik für eine "Vorverarbeitungsnummer" in [lex.ppnumber]

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

Hier ist ein "nicht-stelliges" Zeichen ein beliebiges Zeichen, das in einem anderen Bezeichner als Ziffern verwendet werden kann, und ein "Zeichen" ist entweder + oder -. Spätere Standards würden die Definition erweitern, um einfache Anführungszeichen (C ++ 14) und Sequenzen der Form p-, p +, P-, P + (C ++ 17) zuzulassen.

Das Ergebnis ist, dass in jeder Version des Standards eine Vorverarbeitungsnummer erforderlich ist, um mit einer Ziffer oder einem Punkt gefolgt von einer Ziffer zu beginnen. Danach kann eine beliebige Folge von Ziffern, Buchstaben und Punkten folgen. Daraus folgt, dass unter Verwendung der Maximal-Munch-Regel, obwohl 0.f.T::~T();, als Token gekennzeichnet werden 0.f.T :: ~ T ( ) ;muss0.f.T kein gültiges numerisches Token ist.

Daher ist der Code syntaktisch nicht gültig.

Eric M Schmidt
quelle
Interessanterweise gibt es in [lex.pptoken] tatsächlich ein Beispiel mit anständiger Ähnlichkeit: eel.is/c++draft/lex.pptoken#5
chris
1

Ein benutzerdefiniertes Literal-Suffix, ud-Suffix , ist eine Kennung . Ein Bezeichner ist eine Folge von Buchstaben (einschließlich einiger Nicht-ASCII-Zeichen), dem Unterstrich und Zahlen, die nicht mit einer Zahl beginnen. Das Punktzeichen ist nicht enthalten.

Daher handelt es sich um einen Compiler-Fehler, da die Nicht-Bezeichner-Sequenz f.Tals Bezeichner behandelt wird.

Dies 0.ist eine Bruchkonstante , auf die ein optionaler Exponent folgen kann, dann entweder ein ud-Suffix (für ein benutzerdefiniertes Literal) oder ein Gleitkommasuffix (eines von fFlL). Das fkann auch als ud-Suffx betrachtet werden, aber da es einem anderen Literaltyp entspricht , sollte es das sein und nicht die UDL. Ein ud-Suffix wird in der Grammatik als Bezeichner definiert.

1201Programmalarm
quelle
Warum wird es als ud-Suffix interpretiert?
Vlad aus Moskau
@VladfromMoscow Das 0.ist ein Fractional-Konstante . Darauf kann (mit Ausnahme des Exponentenmaterials) ein ud-Suffix (für ein benutzerdefiniertes Literal) oder ein Gleitkommasuffix (eines von fFlL) folgen . Das fkann auch als ud-Suffx betrachtet werden, aber da es einem anderen Literaltyp entspricht , sollte es das sein und nicht die UDL. Ein ud-Suffix wird in der Grammatik als Bezeichner definiert .
1201ProgramAlarm
@ 1201ProgramAlarm: Während fals ud-Suffix interpretiert werden kann, f.Tsollte nicht wie .nicht in Bezeichner sein. aber es ist ... Ich würde sagen, Compiler-Fehler, aber ziemlich sicher, dass es komplizierter ist.
Jarod42