Sintaks valid memanggil pseudo-destructor untuk konstanta mengambang

9

Pertimbangkan program demonstratif berikut.

#include <iostream>

int main()
{
    typedef float T;

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

Program ini disusun oleh Microsoft Visual Studio Community 2019.

Tapi clangdan gcckeluarkan kesalahan seperti ini

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

Jika menulis ekspresi seperti itu ( 0.f ).T::~T()maka ketiga kompiler mengkompilasi program.

Maka timbul pertanyaan: apakah rekaman ini secara 0.f.T::~T()sintaksis valid? Dan jika tidak, lalu aturan sintaksis apa yang dilanggar?

Vlad dari Moskow
sumber
1
Menempatkan jarak di antara 0.fdan .Tmenyebabkan GCC dan Dentang menerima ini ...
chris
1
Serta(0.f).T::~T();
cigien
Sederhana float f = 1.0f.t;akan menghasilkan kesalahan tentang literal numerik.
1201ProgramAlarm
A floatadalah tipe bawaan , ia tidak memiliki destruktor untuk Anda panggil. Apa yang bahkan Anda lakukan secara manual memanggil destruktor? Di luar wilayah penempatan baru, yang harus menjadi besar tidak-tidak.
Jesper Juhl
@JesparJuhl ini bukan destruktor tetapi destruktor semu, saya baru tahu bahwa itu ada. Info tag memiliki contoh (yang juga memiliki panggilan yang tidak dibenarkan ke destructor btw)
idclev 463035818

Jawaban:

3

Penguraian token numerik cukup kasar, dan memungkinkan banyak hal yang sebenarnya bukan angka yang valid. Di C ++ 98, tata bahasa untuk "nomor preprocessing", ditemukan di [lex.ppnumber], adalah

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

Di sini, "nondigit" adalah karakter apa pun yang dapat digunakan dalam pengidentifikasi, selain digit, dan "tanda" adalah + atau -. Standar selanjutnya akan memperluas definisi untuk memungkinkan tanda kutip tunggal (C ++ 14), dan urutan bentuk p-, p +, P-, P + (C ++ 17).

Hasilnya adalah bahwa, dalam versi standar apa pun, sementara nomor praproses diperlukan untuk memulai dengan digit, atau periode yang diikuti oleh digit, setelah itu urutan angka, huruf, dan periode yang sewenang-wenang dapat mengikuti. Menggunakan aturan munch maksimal, maka yang 0.f.T::~T();diperlukan adalah tokenized 0.f.T :: ~ T ( ) ;, meskipun 0.f.Tbukan token numerik yang valid.

Dengan demikian, kode tersebut tidak valid secara sintaksis.

Eric M Schmidt
sumber
Menariknya, sebenarnya ada contoh dengan kesamaan yang layak di [lex.pptoken]: eel.is/c++draft/lex.pptoken#5
chris
1

Sufiks literal yang ditentukan pengguna, ud-suffix , adalah pengidentifikasi . Sebuah identifier adalah urutan huruf (termasuk beberapa karakter non-ASCII), garis bawah, dan angka yang tidak dimulai dengan angka. Karakter periode tidak termasuk.

Oleh karena itu itu adalah bug kompiler karena memperlakukan urutan non-pengidentifikasi f.Tsebagai pengidentifikasi.

Ini 0.adalah konstanta fraksional , yang dapat diikuti oleh eksponen opsional, lalu sufiks ud (untuk literal yang ditentukan pengguna) atau sufiks floating-point-suffix (salah satu dari fFlL). Itu fdapat dianggap sebagai suf-suffx juga, tetapi karena cocok dengan tipe literal yang lain, seharusnya demikian dan bukan pada UDL. Sebuah ud-akhiran didefinisikan dalam tata bahasa sebagai identifier.

1201ProgramAlarm
sumber
Mengapa itu ditafsirkan sebagai akhiran ud?
Vlad dari Moskow
@ VladfromMoscow 0.adalah konstanta pecahan . Itu dapat diikuti oleh (tidak termasuk hal-hal eksponen) akhiran -ud (untuk literal yang ditentukan pengguna) atau akhiran titik-mengambang (salah satu darifFlL ). Itu fdapat dianggap sebagai suf-suffx juga, tetapi karena cocok dengan tipe literal yang lain, seharusnya demikian dan bukan pada UDL. Sebuah ud-akhiran didefinisikan dalam tata bahasa sebagai identifier .
1201ProgramAlarm
@ 1201ProgramAlarm: Sedangkan fdapat diartikan sebagai ud-suffix, f.Ttidak .boleh tidak bisa di identifier. tapi itu ... Saya akan mengatakan bug compiler tetapi cukup yakin itu lebih rumit.
Jarod42