C++14允许在用户定义字面量中使用数字分隔符吗?

42

尽管clang编译以下行,但g++ 6.1抱怨数字分隔符(请参见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教程“<chrono>教程”中使用10'000s作为示例(在他的演讲中约42分钟)。
请注意,我并没有打算编写“1分钟23秒”,这只是“偶然正确”,因为八进制字面值0123是64 + 16 + 3 == 83。要达到这个目的,我应该写
auto time = 1min + 23s;
但是那种可能会误导的解释并不是问题的一部分。

1
这似乎是一个库的错误,应该进行报告。我的有限实验表明,libstdc++ 定义了错误类型的字面量运算符,采用模板非类型参数 template<char ... _Digits> 而不是 unsigned long long。但这并不是标准所要求的,而且它做错了事情。他们省略了 operator""s(unsigned long long) 运算符,我认为这是基本的根本问题。(他们确实有 operator""s(long double),如所需) - Aaron McDaid
1
错误已在此处报告:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69905(有人发布了此链接,然后删除了他们的评论,但我认为这是正确的链接!) - Aaron McDaid
1
@Aaron McDaid:我已删除了那条评论,并将其包含在我的答案中(请参见下文)。 - René Richter
3个回答

19
如果您查看语法,user-defined-integer-literal 可以是 octal-literal ud-suffix,而 octal-literal 被定义为 0 或者octal-literal ’opt octal-digit

N4140 §2.14.8

用户自定义字面常量:

  • 用户自定义整型字面常量
  • [...]

用户自定义整型字面常量:

  • 八进制字面常量 ud-suffix
  • [...]

N4140 §2.14.2

八进制字面常量:

  • 0
  • 八进制字面常量 ’opt 八进制数字

所以,01'23s 是一个完全有效的字面常量。


5

针对十进制字面量的 WLOG:

[lex.ext]:

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

[lex.icon]:

decimal-literal:
    nonzero-digit
    decimal-literal  opt  digit

也就是说,在 UDLs 中允许使用数字分隔符。


5
这似乎是GCC <chrono> 库实现中的一个错误,正如 @Aaron McDaid 所建议的那样。目前有一份(未经确认的)错误报告: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>头文件后,该错误消失了。

然而,GCC的库实现者可能有意省略了这个版本,以防止不必要的无符号转有符号转换,因为秒被定义为

typedef duration<int64_t> seconds;

编辑:

正如Jonathan Wakely在错误报告的评论中最近指出的那样,与一个开放图书馆工作组问题相关的设计选择没有考虑数字分隔符。


问题在于标准要求进行编译时溢出检查,但使用烹制的字面值运算符无法实现该功能。 - T.C.
我不明白什么是“cooked”运算符,@T.C.。你的意思是“直接”的unsigned long long重载不能在编译时进行检查吗?因此需要使用模板? - Aaron McDaid
@AaronMcDaid 正确。 "cooked" = 取 unsigned long long 的一个; "raw" = 取字符的一个。 - T.C.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接