【问题标题】:Clang's libc++: using long long in the definition of std::chrono::durationClang 的 libc++:在 std::chrono::duration 的定义中使用 long long
【发布时间】:2016-07-18 02:41:12
【问题描述】:

在 32 位平台上的 libc++ 中,int64_t 定义为 long long 的别名。在 64 位平台上:long

另一方面在std::chrono::duration别名的定义中,你可以发现here long long被不小心使用了:

typedef duration<long long,         nano> nanoseconds;
typedef duration<long long,        micro> microseconds;
typedef duration<long long,        milli> milliseconds;
typedef duration<long long              > seconds;
typedef duration<     long, ratio<  60> > minutes;
typedef duration<     long, ratio<3600> > hours;

因此,例如,当我需要严格为 8 个字节长的类型时,我希望

  foo(uint64_t);
  foo(int64_t);

成为一个相当便携的解决方案。但如果是 libc++ 的chrono,则不是这样。除了编写类似于&lt;cstdint&gt; 的自己的逻辑外,没有其他可移植的方法。即,定义foo 的两个附加定义,分别采用long longunsigned long long

或者另一个例子:

  foo(int8_t);
  foo(int16_t);
  foo(int32_t);
  foo(int64_t);

在这种情况下,调用 foo(duration.count()) 会产生歧义。

那么使用不大于long但排名大于long所以不能隐式转换的long long有什么意义?

这是libc++ 的开发者的疏忽吗?

我提出这个的原因是因为 mongodb 的驱动程序不会在 x64 FreeBSD 安装上编译。原因看起来很傻。例如,gccstd::chrono::duration 的定义中使用了int64_t,因此它可以按预期进行编译。

【问题讨论】:

  • 有 64 位平台,其中long 是 32 位。检查 LP64 和 LLP64 平台之间的区别。请注意,这甚至是特定于编译器的,不仅针对平台,尽管通常存在某些约定。
  • @UlrichEckhardt 当然有,但是这有什么关系呢?库定义了&lt;cstdint&gt;,那么为什么不将它用于所述库的其他部分的可移植性呢?
  • 我的意思是,你的前导句是错误的,如果我理解你的问题,完全不相关!难道不是归结为“为什么在一个平台上用uint64_t 定义duration 而在另一个平台上用long long 定义的问题?”顺便说一句:你有 mongodb 构建问题的链接吗?
  • @UlrichEckhardt 问题将很快报告。真正的问题是为什么 libc++ 的开发者让库用户的生活变得更加艰难。
  • 这里的问题到底是什么?

标签: c++ c++11 clang libc++


【解决方案1】:

该标准只要求secondsduration 的typedef,比率为1 和“至少35 位的有符号整数类型”。所以libc++的实现是正确的。

虽然在您的特定情况下使用 int64_t 会减轻可移植性,但这只会让您走这么远。 MSVC 也使用long long,而不是int64_t。 (尽管在这种情况下,它们是相同的类型。)该标准不保证 int64_t 的持续时间,因此即使有其他实现使用它,依赖它也不能移植。

这里的问题不在于 libc++ 的实现做坏事。问题是 C++ 的整数类型有些古怪,尽管intNN_t 类型很方便,但它们并不能完全让您免于了解底层类型。特别是,尝试使用这些 typedef 为 foo 提供完整的重载集是错误的;由于遇到的问题,您需要选择底层类型:重载集可能会或可能不会覆盖long long,您最终会遇到该类型。它发生在 libc++ 的 duration typedefs 而不是其他情况只是巧合。

是的,情况很糟糕,但这个特定问题只是更大问题的一个小症状。

【讨论】:

  • 完全同意你关于整数类型系统的问题。感谢C 它完全搞砸了。另一方面,你会期望这种渐进式库的开发人员有更多的意识:(
【解决方案2】:

我可以在这个问题上发表一些权威意见,因为我是编写此代码的人。虽然其他两个答案非常好,但我已经投了赞成票。

是的,我确实对这些类型进行了一些思考,并考虑根据int_t*typedefs 来定义它们。

我为那些必须超过 32 位的代表选择了long long,其余的选择了long。后者是在将目标从 i386 更改为 x86_64 时,long 将从 32 位更改为 64 位的知识下完成的。

如果我改用int_t*typedefs,其他人很可能也会抱怨这种设计的歧义问题(比如在foo(int)foo(long long) 之间)。很难取悦每个人

我注意到在 mongodb 标头 mongo/src/mongo/util/time_support.h 中它说:

using Microseconds = stdx::chrono::microseconds;
using Milliseconds = stdx::chrono::milliseconds;
using Seconds = stdx::chrono::seconds;
using Minutes = stdx::chrono::minutes;
using Hours = stdx::chrono::hours;

这很容易看起来像:

using Microseconds = stdx::chrono::duration<std::int64_t, stdx::chrono::microseconds::period>;
using Milliseconds = stdx::chrono::duration<std::int64_t, stdx::chrono::milliseconds::period>;
using Seconds = stdx::chrono::duration<std::int64_t, stdx::chrono::seconds::period>;
using Minutes = stdx::chrono::duration<std::int64_t, stdx::chrono::minutes::period>;
using Hours = stdx::chrono::duration<std::int64_t, stdx::chrono::hours::period>;

&lt;chrono&gt; 库使客户可以很容易地创建自定义单元。听起来这可能是 mongodb 的一个很好的解决方案。

【讨论】:

  • 我的论点是:在 C++11 委员会中,我坚信,通过采用&lt;cstdint&gt;,在解决不同平台上某些整数类型的不同大小的可移植性问题上迈出了一小步。出于同样的原因,看到库本身的实现不使用引入的类型是不寻常的:可移植性。
【解决方案3】:

该标准不需要特定的整数类型来表示持续时间。它确实要求该类型可用作 rep 成员类型,因此您可以使用(例如)std::chrono::duration::seconds::rep 作为适合以秒为单位存储值的类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-03
    • 1970-01-01
    • 2014-07-24
    • 2016-12-21
    • 2016-07-20
    • 1970-01-01
    • 2023-01-11
    • 1970-01-01
    相关资源
    最近更新 更多