【问题标题】:Are C++14 digit separators allowed in user defined literals?用户定义的文字中是否允许使用 C++14 位分隔符?
【发布时间】:2017-03-08 19:36:26
【问题描述】:

当 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;

但可能的误导性解释不是问题的一部分。)

【问题讨论】:

  • 这似乎是一个库错误,应该报告。我有限的实验表明libstdc++ 定义了错误类型的文字运算符,采用模板非类型参数template<char ... _Digits> 而不是unsigned long long。但这不是标准所要求的,而且这样做是错误的。他们遗漏了operator""s(unsigned long long) 运算符,我认为这是基本的潜在问题。 (他们确实有operator""s(long double),根据需要)
  • 错误报告在这里:gcc.gnu.org/bugzilla/show_bug.cgi?id=69905(其他人发布了此链接,然后删除了他们的评论,但我认为这是正确的链接!)
  • @Aaron McDaid:我删除了该评论,将其包含在我自己的答案中(见下文)。

标签: c++ c++14 language-lawyer user-defined-literals digit-separator


【解决方案1】:

如果看语法,user-defined-integer-literal可以是octal-literal ud-suffixoctal-literal 定义为 0octal-literal 'opt octal-digit

N4140 §2.14.8

用户定义文字

  • 用户定义的整数文字
  • [...]

用户定义的整数文字

  • 八进制文字 ud-suffix
  • [...]

N4140 §2.14.2

八进制

  • 0
  • 八进制文字'opt八进制数字

所以01'23s 是一个完全有效的文字。

【讨论】:

    【解决方案2】:

    十进制文字的WLOG:

    [lex.ext]:

    用户定义的整数文字:
    十进制文字 ud-suffix

    [lex.icon]:

    十进制文字
        非零数字
        十进制文字 opt 数字

    即是的,UDL 中允许使用数字分隔符。

    【讨论】:

      【解决方案3】:

      正如@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}; }
      

      &lt;chrono&gt; 标头(我的本地安装)错误消失了。

      但是,GCC 的库实现者可能故意遗漏了这个版本,因此他们可以防止不需要的无符号到有符号的转换,因为秒被定义为

      typedef duration<int64_t> seconds;
      

      编辑:

      正如 Jonathan Wakely 最近在错误报告的 cmets 中指出的那样, 该实现是通过设计与一个连接选择的 open Library Working Group issue,但没有考虑数字分隔符。

      【讨论】:

      • 问题是标准要求编译时溢出检查,但使用熟文字运算符不允许您这样做。
      • 我不明白什么是“熟”运算符,@T.C.。您的意思是“直截了当”unsigned long long 重载无法在编译时进行检查吗?因此需要模板?
      • @AaronMcDaid 正确。 “熟” = 一个人拿着unsigned long long; "raw" = 带字符的。
      猜你喜欢
      • 1970-01-01
      • 2012-10-18
      • 1970-01-01
      • 2010-10-19
      • 1970-01-01
      • 1970-01-01
      • 2012-08-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多