Могут ли за числовыми литералами, определенными пользователем, сразу же следовать точка?

Начиная с C++11 стало возможным создавать определяемые пользователем литералы. Как и ожидалось, из таких литералов можно возвращать сложные структуры. Однако при попытке использовать такие операторы, как 123_foo.bar():

struct foo {
    int n;
    int bar() const { return n; }
};

constexpr foo operator ""_foo(unsigned long long test)
{
    return foo{ static_cast<int>(test) };
}

int main() {
    return 123_foo.bar();
}

GCC и Clang отклоняют его, говоря, что не могут найти operator""_foo.bar. MSVC принимает это. Если вместо этого я напишу 123_foo .bar(), все три компилятора примут его

Кто здесь? Является ли 123_foo.bar() действительным?


Некоторая дополнительная информация:


Я склонен полагать, что это ошибка GCC и Clang, поскольку . не является частью действительного идентификатора.


person Justin    schedule 01.03.2018    source источник
comment
Если бы я угадал, по какой-то причине применяется максимальный жевательный   -  person Passer By    schedule 01.03.2018
comment
@PasserBy Но . стоит после идентификатора UDL, поэтому я не понимаю, как здесь применяется максимальное жевание.   -  person Justin    schedule 01.03.2018
comment
Интересный. Кажется, _foo.bar может быть допустимым именем UDL, согласно GCC и Clang!   -  person Nawaz    schedule 01.03.2018
comment
@Наваз Хм. Разве это не означает, что это ошибка GCC и Clang, поскольку грамматика стандарта показывает, что все литералы udl заканчиваются на ud-suffix, что является просто identifier?   -  person Justin    schedule 01.03.2018
comment
Еще одно предположение: токен, начинающийся с цифры, будет включать .. Не могу сейчас погрузиться в правила грамматики. мне кажется где-то ляп   -  person Passer By    schedule 01.03.2018
comment
@Justin: Я так думаю: похоже, это ошибка GCC и Clang, по крайней мере, сообщение об ошибке вводит в заблуждение.   -  person Nawaz    schedule 01.03.2018
comment
@PasserBy Звучит правильно для меня. По той же логике я ожидаю, что 1_xe+2 будет недопустимым, даже если возвращаемый тип operator""_xe предоставляет operator+, принимающий int: e+ также допускается в числах.   -  person    schedule 01.03.2018
comment
@hvd Да, это подпадает под максимальное потребление, как указано в cppreference.   -  person Justin    schedule 01.03.2018
comment
@Justin Как так получилось, что для 1_foo.bar ты этого не видел, а для 1_foe+bar видел? :) Это точно такая же логика для обоих.   -  person    schedule 01.03.2018
comment
@hvd Я неправильно прочитал отрывок из cppreference.   -  person Justin    schedule 01.03.2018
comment
@hvd Я бы сказал, что знак точки является элементом алфавита литерала числа с плавающей запятой, а символ плюса - нет ...   -  person W.F.    schedule 01.03.2018
comment
@В.Ф. А как насчет 1e+5?   -  person Justin    schedule 01.03.2018
comment
@Justin хорошая мысль, хотя после плюса вам придется найти число, например. 1. это допустимый литерал с плавающей запятой   -  person W.F.    schedule 01.03.2018
comment
Совсем недавно отправил отчет об ошибке в MS developercommunity.visualstudio.com/content/problem/203264/ Однако низкие ожидания...   -  person Killzone Kid    schedule 01.03.2018


Ответы (1)


TLDR Clang и GCC верны, вы не можете написать . сразу после определяемого пользователем целочисленного/плавающего литерала, это ошибка MSVC.

Когда программа компилируется, она проходит через 9 фаз трансляции в порядок. Здесь важно отметить, что лексирование (разделение) исходного кода на токены выполняется до того, как будет принято во внимание его семантическое значение.

На этом этапе действует максимальный мунч, то есть токены берутся как самая длинная синтаксически корректная последовательность символов. Например, x+++++y записывается как x ++ ++ + y вместо x + ++ ++ y, даже если первое семантически неверно.

Тогда возникает вопрос, какая самая длинная синтаксически допустимая последовательность для 123_foo.bar. Следуя правилам производства для номера предварительной обработки, точная последовательность

pp-номер → pp-номер идентификатор-нецифра → ... → pp-номер идентификатор-нецифра³ →
pp-номер нецифра³ → pp-номер . нецифра³ → ... → pp-число нецифра⁴ . нецифра³ →
pp-число цифра нецифра⁴ . нецифра³ → ... → pp-число цифра² нецифра⁴ . нецифра³ →
цифра³ нецифра⁴ . нецифра³

Что разрешается в 123_foo.bar, как видно из сообщения об ошибке.

person Passer By    schedule 01.03.2018
comment
Меня вводит в заблуждение, что этого нет в [lex.ext]. - person Justin; 01.03.2018
comment
@Justin: Я могу себе представить множество причин. Представьте себе денежные литералы; они обычно обозначаются трехбуквенными кодами. - person MSalters; 01.03.2018
comment
@Justin Проблема на самом деле возникла до вашего связанного абзаца. Программа сначала закодирована в токены предварительной обработки без какого-либо понятия литералов. Сопоставление токена с литералами происходит позже и является содержанием вашей ссылки. - person Passer By; 01.03.2018
comment
Объясните, пожалуйста, почему преобразование токена pp в требуемый токен и последующий синтаксический анализ не выдает ошибку на этом этапе. Грамматика для суффикса ud ясно указывает, что это идентификатор, и любой токен, который не является действительным идентификатором, должен привести к синтаксической ошибке, не так ли? - person Griwes; 01.03.2018
comment
Чтобы уточнить: я думаю, что это тот же случай, что и с 1..2f, который является допустимым pp-токеном, и интересующие нас компиляторы правильно дают ошибку .2f не является допустимым суффиксом; Точно так же и GCC, и Clang должны выдать ошибку, поскольку _foo.bar не является допустимым суффиксом ud. - person Griwes; 01.03.2018
comment
@Griwes First 1..2f в целом считается токеном препроцессора. Затем он конвертируется в токен. Затем он рассматривается как литерал, после чего компилятор понял, что 1. является самым длинным допустимым плавающим литералом с .2f в качестве суффикса, что приводит к ошибке. Из сообщения об ошибке я могу предположить, что компиляторы решили разрешить поиск имени для получения ошибки, поскольку правила идентификатора требуют такой ошибки, а не еще раз проверяют, является ли суффикс допустимым. - person Passer By; 01.03.2018
comment
Есть ли причина, по которой pp-number идет справа налево? Если он перевернут, чтобы не было левой рекурсии, я думаю, что можно немного изменить грамматику, чтобы не допускать . после идентификатора. - person Justin; 01.03.2018
comment
@Justin Я не автор компиляторов, но я считаю, что правила таковы, что лексирование на этапе 3 невероятно просто - person Passer By; 02.03.2018