用户定义的文字中是否允许使用 C++14 位数字分隔符?
Are C++14 digit separators allowed in user defined literals?
当 clang 编译以下行时,g++ 6.1 抱怨数字分隔符(参见 live example on Coliru):
auto time = 01'23s;
根据 C++14 标准 (N3796),哪个编译器(如果有)是正确的?
否则,是否允许数字分隔符 (§2.14.2) 只是 <chrono>
库 (§20.12.5.8) 的用户定义文字 (§2.14.8) 中的一个实现细节?恕我直言,它不应该,因为这些文字是在 unsigned long long
参数上定义的。
我记得 Howard Hinnant 在他的 CppCon 2016 talk "A <chrono>
tutorial" 中使用 10'000s
作为例子(在他的演讲中大约 42 分钟)。
(请注意,我无意编写“1 分 23 秒”,只是偶然正确,因为八进制文字 0123 是 64 + 16 + 3 == 83。为此我应该写
auto time = 1min + 23s;
但可能的误导性解释不是问题的一部分。)
如果您查看语法,user-defined-integer-literal 可以是 octal-literal ud-suffix,并且 octal-literal 定义为 0
或 octal-literal 'opt octal-digit .
N4140 §2.14.8
user-defined-literal:
- user-defined-integer-literal
- [...]
user-defined-integer-literal:
- octal-literal ud-suffix
- [...]
N4140 §2.14.2
octal-literal:
0
- octal-literal ’opt octal-digit
所以 01'23s
是一个完全有效的文字。
十进制文字的 WLOG:
user-defined-integer-literal:
decimal-literal ud-suffix
decimal-literal:
nonzero-digit
decimal-literal ’
opt
digit
即是的,UDL 中允许使用数字分隔符。
正如@Aaron McDaid 所建议的那样,这似乎是 GCC <chrono>
库实现中的一个错误。有一个(目前未确认的)错误报告:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69905
GCC 的 libstdc++ 为 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>
header(我的本地安装)错误消失了。
但是,GCC 的库实现者可能故意遗漏了这个版本,因此他们可以防止不需要的无符号到有符号的转换,因为秒被定义为
typedef duration<int64_t> seconds;
编辑:
正如 Jonathan Wakely 最近在错误报告的评论中指出的那样,
该实现是通过设计选择的
open Library Working Group issue,但没有考虑数字分隔符。
当 clang 编译以下行时,g++ 6.1 抱怨数字分隔符(参见 live example on Coliru):
auto time = 01'23s;
根据 C++14 标准 (N3796),哪个编译器(如果有)是正确的?
否则,是否允许数字分隔符 (§2.14.2) 只是 <chrono>
库 (§20.12.5.8) 的用户定义文字 (§2.14.8) 中的一个实现细节?恕我直言,它不应该,因为这些文字是在 unsigned long long
参数上定义的。
我记得 Howard Hinnant 在他的 CppCon 2016 talk "A <chrono>
tutorial" 中使用 10'000s
作为例子(在他的演讲中大约 42 分钟)。
(请注意,我无意编写“1 分 23 秒”,只是偶然正确,因为八进制文字 0123 是 64 + 16 + 3 == 83。为此我应该写
auto time = 1min + 23s;
但可能的误导性解释不是问题的一部分。)
如果您查看语法,user-defined-integer-literal 可以是 octal-literal ud-suffix,并且 octal-literal 定义为 0
或 octal-literal 'opt octal-digit .
N4140 §2.14.8
user-defined-literal:
- user-defined-integer-literal
- [...]
user-defined-integer-literal:
- octal-literal ud-suffix
- [...]
N4140 §2.14.2
octal-literal:
0
- octal-literal ’opt octal-digit
所以 01'23s
是一个完全有效的文字。
十进制文字的 WLOG:
user-defined-integer-literal:
decimal-literal ud-suffix
decimal-literal:
nonzero-digit
decimal-literal’
opt digit
即是的,UDL 中允许使用数字分隔符。
正如@Aaron McDaid 所建议的那样,这似乎是 GCC <chrono>
库实现中的一个错误。有一个(目前未确认的)错误报告:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69905
GCC 的 libstdc++ 为 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>
header(我的本地安装)错误消失了。
但是,GCC 的库实现者可能故意遗漏了这个版本,因此他们可以防止不需要的无符号到有符号的转换,因为秒被定义为
typedef duration<int64_t> seconds;
编辑:
正如 Jonathan Wakely 最近在错误报告的评论中指出的那样, 该实现是通过设计选择的 open Library Working Group issue,但没有考虑数字分隔符。