Sintaxe válida de chamada de pseudo-destruidor para uma constante flutuante


9

Considere o seguinte programa demonstrativo.

#include <iostream>

int main()
{
    typedef float T;

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

Este programa é compilado por Microsoft Visual Studio Community 2019.

Mas clange gccemita um erro como este

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

Se escrever a expressão assim ( 0.f ).T::~T(), todos os três compiladores compilarão o programa.

Então surge uma pergunta: esse registro é 0.f.T::~T()sintaticamente válido? E se não, então que regra sintática está quebrada?


11
Colocar um espaço entre 0.fe .Tfaz com que o GCC e o Clang aceitem isso ...
chris

11
Bem como(0.f).T::~T();
cigien 17/04

Um simples float f = 1.0f.t;produzirá o erro sobre o literal numérico.
1201ProgramAlarm

A floaté um tipo embutido , não possui um destruidor para você chamar. O que você está fazendo manualmente chamando destruidores? Fora do território de colocação de novo, isso deve ser um grande não-não.
Jesper Juhl 17/04

@JesparJuhl não é um destruidor, mas um pseudo-destruidor, só sei que ele existe. As informações da tag têm um exemplo (que também possui uma chamada não justificada para o destruidor btw)
idclev 463035818 17/04

Respostas:


3

A análise de tokens numéricos é bastante grosseira e permite muitas coisas que não são realmente números válidos. No C ++ 98, a gramática para um "número de pré-processamento", encontrada em [lex.ppnumber], é

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

Aqui, "sem dígito" é qualquer caractere que possa ser usado em um identificador, exceto dígitos, e um "sinal" é + ou -. Os padrões posteriores expandiriam a definição para permitir aspas simples (C ++ 14) e seqüências no formato p-, p +, P-, P + (C ++ 17).

O resultado é que, em qualquer versão do padrão, enquanto um número de pré-processamento é necessário para iniciar com um dígito ou um período seguido de um dígito, após o qual uma sequência arbitrária de dígitos, letras e períodos pode ser seguida. Usando a regra munch máxima, segue-se que 0.f.T::~T();é necessário tokenizar como 0.f.T :: ~ T ( ) ;, mesmo que 0.f.Tnão seja um token numérico válido.

Portanto, o código não é sintaticamente válido.


Curiosamente, na verdade, há um exemplo com similaridade decente em [lex.pptoken]: eel.is/c++draft/lex.pptoken#5
chris

1

Um sufixo literal definido pelo usuário, ud-suffix , é um identificador . Um identificador é uma sequência de letras (incluindo alguns caracteres não ASCII), o sublinhado e os números que não começam com um número. O caractere de ponto final não está incluído.

Portanto, é um erro do compilador, pois trata a sequência não identificadora f.Tcomo um identificador.

O 0.é uma constante fracionária , que pode ser seguida por um expoente opcional e, em seguida, um sufixo ud (para um literal definido pelo usuário) ou um sufixo de ponto flutuante (um de fFlL). Também fpode ser considerado um ud-suffx , mas como corresponde a outro tipo literal, deve ser esse e não o UDL. Um sufixo-ud é definido na gramática como um identificador.


Por que é interpretado como um sufixo ud?
Vlad de Moscou

@VladfromMoscow O 0.é uma constante fracionária . Isso pode ser seguido por (excluindo o material do expoente) um sufixo ud (para um literal definido pelo usuário) ou um sufixo de ponto flutuante (um dos fFlL). Também fpode ser considerado um ud-suffx , mas como corresponde a outro tipo literal, deve ser esse e não o UDL. Um sufixo-ud é definido na gramática como um identificador .
1201ProgramAlarm

@ 1201ProgramAlarm: Considerando que fpode ser interpretado como ud-sufixo, f.Tnão deve ser como .identificador. mas é ... eu diria um bug do compilador, mas com certeza é mais complicado.
Jarod42 17/04
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.