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 clang
und gcc
geben 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?
c++
syntax
floating-point
c++17
pseudo-destructor
Vlad aus Moskau
quelle
quelle
0.f
und setzen, werden.T
GCC und Clang dies akzeptieren ...(0.f).T::~T();
float f = 1.0f.t;
wird den Fehler über das numerische Literal erzeugen.float
ist 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.Antworten:
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]
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 werden0.f.T :: ~ T ( ) ;
muss0.f.T
kein gültiges numerisches Token ist.Daher ist der Code syntaktisch nicht gültig.
quelle
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.T
als 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 vonfFlL
). Dasf
kann 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.quelle
0.
ist ein Fractional-Konstante . Darauf kann (mit Ausnahme des Exponentenmaterials) ein ud-Suffix (für ein benutzerdefiniertes Literal) oder ein Gleitkommasuffix (eines vonfFlL
) folgen . Dasf
kann 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 .f
als ud-Suffix interpretiert werden kann,f.T
sollte nicht wie.
nicht in Bezeichner sein. aber es ist ... Ich würde sagen, Compiler-Fehler, aber ziemlich sicher, dass es komplizierter ist.