【问题标题】:Cannot convert between std::chrono::time_point s无法在 std::chrono::time_point 之间转换
【发布时间】:2018-12-24 21:00:45
【问题描述】:

为什么下面的函数编译不出来,报错

cannot convert from 'std::chrono::time_point<std::chrono::steady_clock,std::chrono::duration<double,std::nano>>' to 'std::chrono::time_point<std::chrono::steady_clock,std::chrono::steady_clock::duration>'

#include <chrono>

typedef std::chrono::high_resolution_clock::time_point TimePoint;
typedef std::chrono::duration<double, std::ratio<86400>> JulianDays;

TimePoint JulianDaysToUTC(const JulianDays& days)
{
    static const JulianDays EquivalentJulianYearInDays(2451545.0);
    static const JulianDays LeapSecondCorrection(0.0008);
    static const TimePoint CorrectedEpoch = TimePoint() - EquivalentJulianYearInDays + LeapSecondCorrection;
    return CorrectedEpoch + days;
}

注意:TimePoint() 被替换为返回 TimePoint 的函数,但该返回值不/不应该相关。

修改它以使用整数持续时间允许它编译,但我丢失了小数天部分,这是不希望的。

#include <chrono>

typedef std::chrono::high_resolution_clock::time_point TimePoint;
typedef std::chrono::duration<int, std::ratio<86400>> Days;
typedef std::chrono::duration<double, std::ratio<86400>> JulianDays;

TimePoint JulianDaysToUTC(const JulianDays& days)
{
    using std::chrono::duration_cast;
    static const JulianDays EquivalentJulianYearInDays(2451545.0);
    static const JulianDays LeapSecondCorrection(0.0008);
    static const TimePoint CorrectedEpoch = TimePoint() - duration_cast<Days>(EquivalentJulianYearInDays) + duration_cast<Days>(LeapSecondCorrection);
    return CorrectedEpoch + duration_cast<Days>(days);
}

【问题讨论】:

  • 仅供参考:高分辨率时钟的历元通常不固定。同一程序的不同执行可能会有所不同。
  • 我相信对于将要使用它的应用程序,不同执行之间的差异并不重要,只要在同一个执行中它是相同的。不完全确定,但我下周会问。

标签: c++ duration chrono


【解决方案1】:

&lt;chrono&gt; 库的设计使截断错误不会隐式发生。这是因为截断错误很容易发生,并且经常导致信息意外丢失。

错误信息:

无法从time_point&lt;steady_clock, duration&lt;double,std::nano&gt;&gt; 转换 给time_point&lt;steady_clock, steady_clock::duration&gt;

表示已尝试从小数纳秒(基于双精度)到整纳秒(基于整数)的隐式转换,但不允许。事实证明,每个steady_clock::duration 恰好是纳秒,尽管没有指定。

如果您想要截断(如本例所示),可以使用duration_casttime_point_cast 将截断到零。在 C++17 中,添加了floorceilround 截断模式。

这是执行库隐式拒绝执行的截断转换的最直接方法:

#include <chrono>

typedef std::chrono::high_resolution_clock::time_point TimePoint;
typedef std::chrono::duration<double, std::ratio<86400>> JulianDays;

TimePoint JulianDaysToUTC(const JulianDays& days)
{
    static const JulianDays EquivalentJulianYearInDays(2451545.0);
    static const JulianDays LeapSecondCorrection(0.0008);
    static const TimePoint CorrectedEpoch =
        std::chrono::time_point_cast<TimePoint::duration>(
            TimePoint() - EquivalentJulianYearInDays + LeapSecondCorrection);
    return std::chrono::time_point_cast<TimePoint::duration>(CorrectedEpoch + days);
}

第一次转换是必要的,因为表达式TimePoint() - EquivalentJulianYearInDays + LeapSecondCorrection 的类型为time_point&lt;high_resolution_clock, duration&lt;double, nano&gt;&gt;(浮点纳秒时间点),而目标类型是基于整数的纳秒时间点。第二次转换也是如此。

auto 可用于稍微清理此代码,并避免其中一种转换:

#include <chrono>

typedef std::chrono::high_resolution_clock::time_point TimePoint;
typedef std::chrono::duration<double, std::ratio<86400>> JulianDays;

TimePoint JulianDaysToUTC(const JulianDays& days)
{
    static const JulianDays EquivalentJulianYearInDays(2451545.0);
    static const JulianDays LeapSecondCorrection(0.0008);
    static const auto CorrectedEpoch = TimePoint() -
                                       EquivalentJulianYearInDays + LeapSecondCorrection;
    return std::chrono::time_point_cast<TimePoint::duration>(CorrectedEpoch + days);
}

现在CorrectedEpoch 是基于双纳秒的时间点,但该细节对您的算法并不重要。


此外,Nicol Bolas 关于 high_resolution_clock 的可疑使用的评论是有根据的。如果您从不将TimePoint 与来自high_resolution_clock::now()high_resolution_clock::time_point 混合使用,您的代码可能会起作用。但是,使用记录的 2000-01-01 12:00:00 UTC 纪元创建自己的自定义时钟会更安全。那么任何意外的混合都会在编译时被捕获。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-08
    • 1970-01-01
    • 2015-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-13
    相关资源
    最近更新 更多