Soru C ++ std :: chrono :: time_point öğesini uzun ve geriye nasıl dönüştürebilirim


Dönüştürmem gerek std::chrono::time_point ve için long tipi (tamsayı 64 bit). Ben çalışmaya başlıyorum std::chrono ...

İşte kodum:

int main ()
{
     std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

    auto epoch = now.time_since_epoch();
    auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
    long duration = value.count();


    std::chrono::duration<long> dur(duration);

    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

Bu kod derleniyor ama başarı göstermiyor.

Neden ki dt bundan farklı now sonunda?

Bu kodda eksik olan nedir?


32
2017-07-06 20:58


Menşei


Chrono kütüphanesine fazla aşina değilim ama kullanmak zorunda olduğuna inanıyorum. std::chrono::duration<long,std::milli> dur ve hatta o zaman, yuvarlama hataları alabilirsiniz (std::chrono::system_clock Muhtemelen milisaniyeden daha yüksek bir çözünürlüğe sahiptir). - MikeMB


Cevaplar:


std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

Bu harika bir yer auto:

auto now = std::chrono::system_clock::now();

Trafiğe girmek istediğinizden beri millisecond hassas, devam etmek ve ona gizlemek iyi olurdu time_point:

auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

now_ms bir time_point, dayalı system_clockama doğrusuyla milliseconds ne olursa olsun kesin olarak system_clock vardır.

auto epoch = now_ms.time_since_epoch();

epoch şimdi türü var std::chrono::milliseconds. Ve bu sonraki ifade aslında bir no-op haline gelir (sadece bir kopya yapar ve bir dönüşüm yapmaz):

auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);

İşte:

long duration = value.count();

Hem senin hem de kodumda duration sayısını tutar milliseconds çağından beri system_clock.

Bu:

std::chrono::duration<long> dur(duration);

Bir oluşturur duration ile temsil edilen longve bir doğruluk seconds. Bu etkili reinterpret_casts milliseconds tutuldu value için seconds. Bu bir mantık hatasıdır. Doğru kod şöyle görünecektir:

std::chrono::milliseconds dur(duration);

Bu hat:

std::chrono::time_point<std::chrono::system_clock> dt(dur);

bir oluşturur time_point dayalı system_clock, hassas bir şekilde tutma yeteneği ile system_clockdoğal hassasiyet (genellikle milisaniyeden daha ince). Ancak, çalışma zamanı değeri, milisaniye sayısının tümünün tutulduğunu doğru olarak yansıtacaktır. dur).

Düzeltme ile bile olsa, bu test (neredeyse her zaman) başarısız olacaktır:

if (dt != now)

Çünkü dt ayrılmaz bir sayı tutar milliseconds, fakat now benden daha ince keneler bir bütünlük içerir millisecond (Örneğin. microseconds veya nanoseconds). Böylece sadece nadiren şansa system_clock::now() ayrılmaz bir sayı verdi milliseconds Test geçerdi.

Ama bunun yerine yapabilirsiniz:

if (dt != now_ms)

Ve şimdi beklenen sonucunuzu güvenilir bir şekilde alacaksınız.

Hepsini bir araya koy:

int main ()
{
    auto now = std::chrono::system_clock::now();
    auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

    auto value = now_ms.time_since_epoch();
    long duration = value.count();

    std::chrono::milliseconds dur(duration);

    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    if (dt != now_ms)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

Şahsen tüm buluyorum std::chrono aşırı tempolu ve bu yüzden şöyle kod olurdu:

int main ()
{
    using namespace std::chrono;
    auto now = system_clock::now();
    auto now_ms = time_point_cast<milliseconds>(now);

    auto value = now_ms.time_since_epoch();
    long duration = value.count();

    milliseconds dur(duration);

    time_point<system_clock> dt(dur);

    if (dt != now_ms)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

Hangi güvenilir çıktı:

Success.

Son olarak, arasında dönüştürme kod azaltmak için time_point ve integral tipi minimum. Bu dönüşümler tehlikelidir ve bu nedenle, daha az kod, çıplak ayrılmaz türünü işlemek daha iyi yazarsınız:

int main ()
{
    using namespace std::chrono;
    // Get current time with precision of milliseconds
    auto now = time_point_cast<milliseconds>(system_clock::now());
    // sys_milliseconds is type time_point<system_clock, milliseconds>
    using sys_milliseconds = decltype(now);
    // Convert time_point to signed integral type
    auto integral_duration = now.time_since_epoch().count();
    // Convert signed integral type to time_point
    sys_milliseconds dt{milliseconds{integral_duration}};
    // test
    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

Yukarıdaki ana tehlike değil yorumlama integral_duration gibi milliseconds dönüş yolunda time_point. Bu riski azaltmanın bir yolu yazmaktır:

    sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};

Bu, riski kullandığınızdan emin olmak için azalır. sys_milliseconds çıkış yolunda ve iki yerde geri dönüş yolunda.

Ve bir örnek daha: Ne olursa olsun süreyi temsil eden bir integralden dönüştürmek istediğinizi varsayalım. system_clock destekler (microseconds, 10inci mikrosaniye veya nanosaniye). O zaman, yukarıdaki gibi milisaniye belirtmekle ilgili endişelenmenize gerek yok. Kod basitleştirir:

int main ()
{
    using namespace std::chrono;
    // Get current time with native precision
    auto now = system_clock::now();
    // Convert time_point to signed integral type
    auto integral_duration = now.time_since_epoch().count();
    // Convert signed integral type to time_point
    system_clock::time_point dt{system_clock::duration{integral_duration}};
    // test
    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

Bu çalışır, ancak dönüşümün yarısını (integral olarak) bir platformda ve diğer yarısında (integralden) başka bir platformda çalıştırırsanız, system_clock::durationiki dönüşüm için farklı hassasiyetler olacaktır.


80
2017-07-07 02:17



Çok açık ve yardımsever. Teşekkürler! - Mendes
@BrentNash: Dikkat et, seni bu konuda alabilirim. ;-) Cppcon 2015'te olacağım (cppcon.org) bunun hakkında konuşmak: howardhinnant.github.io/date_v2.html . Konu çok yakından ilişkilidir time_point_cast<milliseconds>(now) Yukarıdaki cevabımda. Sadece süre courser: time_point_cast<days>(now). - Howard Hinnant
Son yorumda yazım hatası: daha kaba, değil koç. Büyük cevap olsa da. - Dirk Eddelbuettel
İngilizce sorunu, bir C ++ derleyicisi ile ayrıştırılamaz ve derleyici daha iyi bir yazım denetimi yapar. :-) - Howard Hinnant
Her yerde 'auto' kullanmıyor olsaydınız bir sekme biraz daha iyi olacağını düşünürsem de bu çok yararlı. Sadece benim gibi tembel insanlar için başka bir yere bakmak zorunda kalmadan ne tür manipüle edildiğini görmek ister. Teşekkürler bir demet @HowardHinnant - Markus L.


Ayrıca, zaman noktasında ms sayısını elde etmenin iki yolu olduğunu da belirtmek isterim. Hangisinin daha iyi olduğundan emin değilim, onları kıyasladım ve her ikisinin de aynı performansı var, bu yüzden bir tercih meselesi. Belki Howard şunları yapabilir:

auto now = system_clock::now();

//Cast the time point to ms, then get its duration, then get the duration's count.
auto ms = time_point_cast<milliseconds>(now).time_since_epoch().count();

//Get the time point's duration, then cast to ms, then get its count.
auto ms = duration_cast<milliseconds>(tpBid.time_since_epoch()).count();

İlki aklımda soldan sağa doğru daha net bir şekilde okunuyor.


1
2018-03-31 18:04





time_point nesneleri sadece diğerleriyle aritmetik desteği time_point veya duration nesneler.

Dönüştürmeniz gerekir long bir duration Belirtilen birimlerden sonra kodunuz doğru şekilde çalışmalıdır.


0
2017-07-06 21:04



Bir örnek gönderebilir misin? - Mendes
Sağlanan her iki bağlantının da alt kısmında bir "Örnek" bölümü vardır. - Mr. Llama
Derlemeyi yaptım, ama bazı mantık hataları var ... Orijinal kodu düzenledim ... - Mendes
Örnekleri dahil etmek için cevabı yararlı olacaktır. Linkler ölür ya da değişir. Bu söylendi, neden bu downvoted emin değilim. - TankorSmash