Невозможно конвертировать между std :: chrono :: time_point s - PullRequest
0 голосов
/ 25 декабря 2018

Почему не скомпилируется следующая функция с ошибкой

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 голосов
/ 25 декабря 2018

Библиотека <chrono> разработана таким образом, чтобы ошибка усечения не возникала неявно.Это связано с тем, что ошибка усечения может легко возникнуть и часто приводит к случайной потере информации.

Сообщение об ошибке:

не может быть преобразовано из time_point<steady_clock, duration<double,std::nano>> в time_point<steady_clock, steady_clock::duration>

говорит, что неявное преобразование из дробных наносекунд (двойных) в целые наносекунды (целых) было предпринято, но не разрешено.Оказывается, что каждые steady_clock::duration оказываются наносекундами, хотя это не указано.

Если вы хотите усечение (как в этом случае), можно использовать duration_cast или time_point_cast для усеченияк нулю.В C ++ 17 добавлены режимы усечения floor, ceil и round.

Вот наиболее простой способ выполнения приведения усечения, который библиотека отказывается делать неявно:

#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>> (точка-точка наносекунды с плавающей точкой), а тип назначения - целая точка-наносекунды времени.То же самое для второго преобразования.

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, но эта деталь не очень важна для вашего алгоритма.


Кроме того, оправдан комментарий Николя Боласа о подозрительном использовании high_resolution_clock.Ваш код может работать, если вы никогда не смешаете TimePoint с high_resolution_clock::time_point, полученным с high_resolution_clock::now().Однако вам будет безопаснее просто создать свои собственные часы с документированной эпохой 2000-01-01 12:00:00 UTC.Тогда любое случайное смешивание будет обнаружено во время компиляции.

...