Рассмотрим следующую демонстрационную программу.
#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()
синтаксически достоверной? А если нет, то какое синтаксическое правило нарушено?
c++
syntax
floating-point
c++17
pseudo-destructor
Влад из Москвы
источник
источник
0.f
и.T
заставляет их принять это ...(0.f).T::~T();
float f = 1.0f.t;
выдаст ошибку о числовом литерале.float
является встроенным типом, он не имеет деструктора для вызова. Что вы вообще делаете, вручную вызывая деструкторы? За пределами места размещения - новая территория, это должно быть большим нет-нет.Ответы:
Разбор числовых токенов довольно грубый и допускает множество вещей, которые на самом деле не являются действительными числами. В C ++ 98 грамматика для «числа предварительной обработки», найденная в [lex.ppnumber], имеет вид
Здесь «нецифровый» - это любой символ, который может использоваться в идентификаторе, кроме цифр, а «знак» - это либо +, либо -. Более поздние стандарты расширили определение, чтобы разрешить одинарные кавычки (C ++ 14) и последовательности в форме p-, p +, P-, P + (C ++ 17).
В результате в любой версии стандарта номер предварительной обработки должен начинаться с цифры или с периода, за которым следует цифра, после чего может следовать произвольная последовательность цифр, букв и периодов. Из правила максимального мунка следует, что
0.f.T::~T();
его необходимо маркировать как0.f.T :: ~ T ( ) ;
, хотя0.f.T
он и не является допустимым числовым токеном.Таким образом, код не является синтаксически допустимым.
источник
Пользовательский литеральный суффикс ud-суффикс является идентификатором . Идентификатор представляет собой последовательность букв (включая некоторые символы не-ASCII), подчеркивание и цифры , которые не начинаются с цифрой. Символ точки не включен.
Следовательно, это ошибка компилятора, поскольку он обрабатывает неидентификатор последовательности
f.T
как идентификатор.0.
Является дробно-константой , которая может сопровождаться дополнительным показателем, то либо с удами-суффиксом (для определенных буквального пользователя) или с плавающей точкой-суффиксом (один изfFlL
).f
Можно считать уд-suffx , как хорошо, но так как он соответствует другому буквальным типа он должен быть, а не UDL. Уд-суффикс определяется в грамматике в качестве идентификатора.источник
0.
является дробным постоянной . За этим может следовать (исключая экспоненту) ud-суффикс (для пользовательского литерала) или суффикс с плавающей точкой (один изfFlL
).f
Можно считать уд-suffx , как хорошо, но так как он соответствует другому буквальным типа он должен быть, а не UDL. Уд-суффикс определяется в грамматике в качестве идентификатора .f
можно интерпретировать как ud-суффикс,f.T
а.
не как в идентификаторе. но это ... Я бы сказал, ошибка компилятора, но уверен, что это сложнее.