无法在std :: chrono :: time_point之间转换

时间:2018-12-24 21:00:46

标签: c++ duration chrono

为什么以下函数不会编译,并显示错误

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);
}

1 个答案:

答案 0 :(得分:1)

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

错误消息:

  

无法从time_point<steady_clock, duration<double,std::nano>>进行转换   到time_point<steady_clock, steady_clock::duration>

表示已经尝试了从分数纳秒(基于双精度)到整个纳秒(基于整数)的隐式转换,但不允许这样做。事实证明,每个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<high_resolution_clock, duration<double, nano>>(浮点纳秒time_point),而目的地类型是基于整数的纳秒time_point。同上进行第二次转换。

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是一个基于双精度的纳秒time_point,但是该细节对于您的算法而言并不重要。


此外,Nicol Bolas对high_resolution_clock可疑使用的评论也是有根据的。如果您从未将TimePoint与来自high_resolution_clock::time_point的{​​{1}}混合使用,则您的代码可能会起作用。但是,使用记录在案的2000-01-01 12:00:00 UTC纪元创建自己的自定义时钟会更安全。然后,任何意外的混合都会在编译时被捕获。