Дійсний синтаксис виклику псевдодеструктора для плаваючої константи


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
Розміщення пробілу між ними 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

Відповіді:


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 .

Тут "nondigit" - це будь-який символ, який можна використовувати в ідентифікаторі, крім цифр, а "знак" - або +, або -. Пізніші стандарти розширять визначення, щоб дозволити одинарні лапки (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
chris

1

Буквально визначений користувачем буквальний суфікс - ud-суфікс - це ідентифікатор . Ідентифікатор є послідовністю букв (включаючи деякі символи НЕ-ASCII), підкреслення і цифри , які не починаються з цифрою. Символ періоду не включений.

Тому це помилка компілятора, оскільки вона розглядає послідовність неідентифікатора f.Tяк ідентифікатор.

Це 0.- константа дробу , за якою може супроводжуватися необов'язковий показник, то або суффікс ud (для визначеного користувачем літералу), або суфікс із плаваючою комою (один із fFlL). Так само fможна вважати суффікс ud , але оскільки він відповідає іншому буквальному типу, він повинен бути таким, а не UDL. Уд-суфікс визначається в граматиці в якості ідентифікатора.


Чому його трактують як суфікс ud?
Влад з Москви

@VladfromMoscow 0.є дробовим постійної . Після цього може супроводжуватися (виключаючи матеріал експонента) суффікс ud (для визначеного користувачем літералу) або суфікс з плаваючою комою (один із fFlL). Так само fможна вважати суффікс ud , але оскільки він відповідає іншому буквальному типу, він повинен бути таким, а не UDL. Уд-суфікс визначається в граматиці в якості ідентифікатора .
1201ProgramAlarm

@ 1201ProgramAlarm: Оскільки fможна інтерпретувати як суффікс ud, f.Tвін не може бути таким, що не .може бути в ідентифікаторі. але це ... Я б сказав, помилка компілятора, але впевнений, що це складніше.
Jarod42
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.