Допустимый синтаксис вызова псевдодеструктора для плавающей константы

9

Рассмотрим следующую демонстрационную программу.

#include <iostream>

int main()
{
    typedef float T;

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

Эта программа составлена Microsoft Visual Studio Community 2019.

Но clangи gccвыдать ошибку, как это

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
Помещение пробела между GCC и Clang 0.fи .Tзаставляет их принять это ...
Крис
1
А также(0.f).T::~T();
сигиен
Простое float f = 1.0f.t;выдаст ошибку о числовом литерале.
1201ProgramAlarm
A floatявляется встроенным типом, он не имеет деструктора для вызова. Что вы вообще делаете, вручную вызывая деструкторы? За пределами места размещения - новая территория, это должно быть большим нет-нет.
Джеспер Юл
@JesparJuhl это не деструктор, а псевдо-деструктор, я просто узнал, что он существует. У информации тега есть пример (который также имеет
необоснованный

Ответы:

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).

В результате в любой версии стандарта номер предварительной обработки должен начинаться с цифры или с периода, за которым следует цифра, после чего может следовать произвольная последовательность цифр, букв и периодов. Из правила максимального мунка следует, что 0.f.T::~T();его необходимо маркировать как 0.f.T :: ~ T ( ) ;, хотя 0.f.Tон и не является допустимым числовым токеном.

Таким образом, код не является синтаксически допустимым.

Эрик М Шмидт
источник
Интересно, что на самом деле есть пример с приличным сходством в [lex.pptoken]: eel.is/c++draft/lex.pptoken#5
Крис
1

Пользовательский литеральный суффикс ud-суффикс является идентификатором . Идентификатор представляет собой последовательность букв (включая некоторые символы не-ASCII), подчеркивание и цифры , которые не начинаются с цифрой. Символ точки не включен.

Следовательно, это ошибка компилятора, поскольку он обрабатывает неидентификатор последовательности f.Tкак идентификатор.

0.Является дробно-константой , которая может сопровождаться дополнительным показателем, то либо с удами-суффиксом (для определенных буквального пользователя) или с плавающей точкой-суффиксом (один из fFlL). fМожно считать уд-suffx , как хорошо, но так как он соответствует другому буквальным типа он должен быть, а не UDL. Уд-суффикс определяется в грамматике в качестве идентификатора.

1201ProgramAlarm
источник
Почему это интерпретируется как ud-суффикс?
Влад из Москвы
@VladfromMoscow 0.является дробным постоянной . За этим может следовать (исключая экспоненту) ud-суффикс (для пользовательского литерала) или суффикс с плавающей точкой (один из fFlL). fМожно считать уд-suffx , как хорошо, но так как он соответствует другому буквальным типа он должен быть, а не UDL. Уд-суффикс определяется в грамматике в качестве идентификатора .
1201ProgramAlarm
@ 1201ProgramAlarm: тогда как fможно интерпретировать как ud-суффикс, f.Tа .не как в идентификаторе. но это ... Я бы сказал, ошибка компилятора, но уверен, что это сложнее.
Jarod42