std::chrono::time_point
をlong
型(整数64ビット)との間で変換する必要があります。 std::chrono
の使用を開始しています...
ここに私のコードがあります:
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;
}
このコードはコンパイルされますが、成功を示しません。
最後にdt
がnow
と異なるのはなぜですか?
そのコードには何が欠けていますか?
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
これはauto
に最適な場所です。
auto now = std::chrono::system_clock::now();
millisecond
の精度でトラフィッキングしたいので、time_point
でそれを秘密にしておくとよいでしょう。
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
now_ms
はtime_point
に基づくsystem_clock
ですが、system_clock
の精度ではなく、milliseconds
の精度を持ちます。
auto Epoch = now_ms.time_since_Epoch();
Epoch
のタイプはstd::chrono::milliseconds
になりました。そして、この次のステートメントは本質的にノーオペレーションになります(単にコピーを作成し、変換を行いません):
auto value = std::chrono::duration_cast<std::chrono::milliseconds>(Epoch);
ここに:
long duration = value.count();
あなたと私のコードの両方で、duration
はsystem_clock
のエポック以降のmilliseconds
の数を保持します。
この:
std::chrono::duration<long> dur(duration);
duration
、およびlong
の精度で表されるseconds
を作成します。これは、実質的にreinterpret_cast
s milliseconds
がvalue
からseconds
に保持します。これは論理エラーです。正しいコードは次のようになります。
std::chrono::milliseconds dur(duration);
この行:
std::chrono::time_point<std::chrono::system_clock> dt(dur);
time_point
に基づいてsystem_clock
を作成します。精度はsystem_clock
のネイティブの精度(通常はミリ秒よりも細かい)を保持します。ただし、実行時の値は、ミリ秒の整数が保持されていることを正しく反映します(dur
のタイプの修正を前提としています)。
ただし、修正しても、このテストは(ほぼ常に)失敗します。
if (dt != now)
dt
はmilliseconds
の整数を保持しますが、now
はmillisecond
よりも細かいティックの整数を保持するため(例:microseconds
またはnanoseconds
)。したがって、system_clock::now()
がmilliseconds
の整数を返したまれな場合にのみ、テストに合格します。
しかし、代わりに次のことができます。
if (dt != now_ms)
これで、期待どおりの結果が確実に得られます。
すべてを一緒に入れて:
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;
}
個人的に私はすべてのstd::chrono
が過度に冗長であるため、次のようにコーディングします。
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;
}
確実に出力されます:
Success.
最後に、time_point
と整数型の間のコード変換を最小限に抑えるために、一時的なものを削除することをお勧めします。これらの変換は危険であるため、裸の整数型を操作するコードが少ないほど良いです。
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;
}
上記の主な危険は、integral_duration
に戻る途中でtime_point
をmilliseconds
として解釈するnotです。そのリスクを軽減する1つの可能な方法は、次のように書くことです。
sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};
これにより、sys_milliseconds
を使用して帰路と帰路の2か所で使用するだけで、リスクが軽減されます。
そしてもう一つの例:system_clock
がサポートする期間(マイクロ秒、10th マイクロ秒またはナノ秒)。その後、上記のようにミリ秒を指定することを心配する必要はありません。コードは次のように単純化されます。
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;
}
これは機能しますが、一方のプラットフォームで半分の変換(積分への変換)を実行し、別のプラットフォームで残りの半分(積分からの変換)を実行すると、2つの変換に対してsystem_clock::duration
の精度が異なるというリスクが発生します。
また、その時点でミリ秒数を取得する方法は2つあります。どちらが優れているかはわかりませんが、それらをベンチマークしましたが、どちらも同じパフォーマンスを持っているので、好みの問題だと思います。おそらく、ハワードは次のようにチャイムを鳴らすことができました。
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();
最初のものは、私の心の中で左から右に向かってよりはっきりと読みます。
time_point
オブジェクト は、他のtime_point
またはduration
オブジェクトとの算術演算のみをサポートします。
long
を指定された単位の duration
に変換する必要があります。そうすれば、コードは正しく機能するはずです。
単一行として:
long value_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()).time_since_Epoch()).count();