Разрешены ли 14-значные разделители C++ в пользовательских литералах?

В то время как clang компилирует следующую строку, g++ 6.1 жалуется на разделитель цифр (см. Пример на Coliru):

auto time = 01'23s;

Какой компилятор, если таковой имеется, является правильным в соответствии со стандартом C++14 (N3796)?

В противном случае разрешается использование разделителей цифр (§2.14.2) только в деталях реализации пользовательских литералов (§2.14.8) <chrono> библиотека (§20.12.5.8)? ИМХО так быть не должно, так как эти литералы определены на unsigned long long параметры.

Я помню, как Говард Хиннант использовал 10'000s в качестве примера во время своего выступления на CppCon 2016 <chrono> учебник " (около 42 минут в своем выступлении).


(Обратите внимание, что я не собирался кодировать "1 минуту и ​​23 секунды", что является правильным только случайно, поскольку восьмеричный литерал 0123 равен 64 + 16 + 3 == 83. Для этой цели я должен написать

auto time = 1min + 23s;

но это возможное вводящее в заблуждение толкование не является частью вопроса.)

3 ответа

Решение

Если вы посмотрите на грамматику, то определяемый пользователем целочисленный литерал может быть восьмеричным литералом ud-суффикс, а восьмеричный литерал определяется как 0 или восьмерично-буквальноеopt восьмеричное число.

N4140 §2.14.8

пользовательский-литерал:

  • определяемый пользователь целочисленного-буквальная
  • [...]

пользовательский-целочисленный-литерал:

  • восьмерично-буквальный ud-суффикс
  • [...]

N4140 §2.14.2

восьмерично-буквальное:

  • 0
  • восьмерично-буквальныйopt восьмерично-цифровой

Так 01'23s это совершенно действительный литерал.

WLOG для десятичных литералов:

[lex.ext]:

определяемого пользователь целочисленного-буквальный:
десятичный-буквенный ud-суффикс

[lex.icon]:

десятичное-буквенное:
ненулевая цифра
десятичный литерал выбрать цифру

Т.е. да, в UDL допускаются разделители цифр.

Это похоже на ошибку в реализации GCC <chrono> библиотека, как предложил Аарон МакДейд. Существует (в настоящее время неподтвержденное) сообщение об ошибке: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69905

LibstdC++ GCC реализует две подписи для std::chrono_literals:

constexpr chrono::duration<long double>
operator""s(long double __secs)
{ return chrono::duration<long double>{__secs}; }

template <char... _Digits>
  constexpr chrono::seconds
  operator""s()
  { return __check_overflow<chrono::seconds, _Digits...>(); }

Версия шаблона с ошибкой не требуется стандартом. При добавлении

constexpr chrono::seconds
operator""s(unsigned long long __secs)
{ return chrono::seconds{__secs}; }

к <chrono> заголовок (моей локальной установки) ошибка исчезает.

Однако разработчики библиотеки GCC могли специально исключить эту версию, чтобы предотвратить нежелательное преобразование неподписанных в подписанные, поскольку секунды определены как

typedef duration<int64_t> seconds;

Редактировать:

Как недавно отметил Джонатан Уэйкли в комментариях к отчету об ошибке, реализация была выбрана по проекту в связи с вопросом об открытой рабочей группе библиотеки, но не учитывала разделители цифр.

Другие вопросы по тегам