Разрешены ли 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 для десятичных литералов:
определяемого пользователь целочисленного-буквальный:
десятичный-буквенный ud-суффикс
десятичное-буквенное:
ненулевая цифра
десятичный литерал’
выбрать цифру
Т.е. да, в 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;
Редактировать:
Как недавно отметил Джонатан Уэйкли в комментариях к отчету об ошибке, реализация была выбрана по проекту в связи с вопросом об открытой рабочей группе библиотеки, но не учитывала разделители цифр.