用户定义的文字中是否允许使用 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 定义为 0octal-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:

[lex.ext]:

user-defined-integer-literal:
    decimal-literal ud-suffix

[lex.icon]:

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,但没有考虑数字分隔符。