目錄
一 chrono庫
- C++ 標準庫chrono中有三個比較重要的概念,它們分別是:
- clocks
- time points
- durations
- 本文主要對 duration 概念進行討論。
二 duration
- duration表示時間間隔或者說時間段,例如:42秒。42叫做tick數, 秒是單位。
A duration consists of a span of time, defined as some number of ticks of some time unit. For example, “42 seconds” could be represented by a duration consisting of 42 ticks of a 1-second time unit.
- 定義於頭文件 < chrono >
template<class Rep, class Period = std::ratio<1>>
class duration; (since C++11)
- 由定義也能看出,duration 是一個數值和一個分數的組合。
- 數值類型是Rep, 表示 tick數(計次數);
- 分數表示時間單位,類型是具化的ration類型,默認是std::ratio<1>, 表示1秒。
- std::ratio 請參考此前文章 C++11 std::ratio
三 成員類型
- rep 表示計次類型
- period 表示時間單位(計次週期)類型
四 Dem輔助函數
- 下面Demo用到的輔助函數如下:
template<class DurationT>
void print(const std::string pre, const DurationT& d) {
std::cout << "(" << pre << ")";
std::cout << ".count(): " << d.count() << std::endl;
}
五 成員函數
1 構造函數
- 定義
constexpr duration() = default;(1)(since C++11)
duration( const duration& ) = default;(2)(since C++11)
template< class Rep2 >
constexpr explicit duration( const Rep2& r );(3)(since C++11)
template< class Rep2, class Period2 >
constexpr duration( const duration<Rep2,Period2>& d );(4)(since C++11)
2 count
- 返回計次數
- Demo
std::chrono::duration<int, std::ratio<1,2>> d1 {10};
print("d1", d1);
- 結果
(d1).count(): 10
3 zero min max [static]
- 返回特殊duration值
- Demo
std::chrono::duration<uint8_t, std::ratio<1>>::zero());
std::chrono::duration<uint8_t, std::ratio<1>>::min());
std::chrono::duration<uint8_t, std::ratio<1>>::max());
4 operator+ operator-(unary)
- 一元加減
- 定義
constexpr duration operator+() const;(1)(until C++17)
constexpr std::common_type_t<duration> operator+() const;(1)(since C++17)
constexpr duration operator-() const;(2)(until C++17)
constexpr std::common_type_t<duration> operator-() const;(2)(since C++17)
- Demo
std::chrono::duration<int, std::ratio<1,2>> d1 {10};
print("d1", d1);
std::chrono::duration<int, std::ratio<1,2>> d2 = +d1;
print("d2", d2);
d2 = -d1;
print("d2", d2);
- 結果
(d1).count(): 10
(d2).count(): 10
(d2).count(): -10
5 operator++ operator–
- 遞增、遞減tick數
- 定義
duration& operator++();(1)(C++17 前)
constexpr duration& operator++();(1)(C++17 起)
duration operator++(int);(2)(C++17 前)
constexpr duration operator++(int);(2)(C++17 起)
duration& operator--();(3)(C++17 前)
constexpr duration& operator--();(3)(C++17 起)
duration operator--(int);(4)(C++17 前)
constexpr duration operator--(int);(4)(C++17 起)
- Demo
std::chrono::duration<int, std::ratio<1, 2>> d1{10};
print("d1", d1);
print("d1++", d1++);
print("d1--", d1--);
print("++d1", ++d1);
print("--d1", --d1);
- 結果
(d1).count(): 10
(d1++).count(): 10
(d1--).count(): 11
(++d1).count(): 11
(--d1).count(): 10
6 compound assignment
- 兩個duration複合賦值(+= -= *= /= %=)
- 定義
duration& operator+=(const duration& d);(1)(until C++17)
constexpr duration& operator+=(const duration& d);(1)(since C++17)
duration& operator-=(const duration& d);(2)(until C++17)
constexpr duration& operator-=(const duration& d);(2)(since C++17)
duration& operator*=(const rep& rhs);(3)(until C++17)
constexpr duration& operator*=(const rep& rhs);(3)(since C++17)
duration& operator/=(const rep& rhs);(4)(until C++17)
constexpr duration& operator/=(const rep& rhs);(4)(since C++17)
duration& operator%=(const rep& rhs);(5)(until C++17)
constexpr duration& operator%=(const rep& rhs);(5)(since C++17)
duration& operator%=(const duration& rhs);(6)(until C++17)
constexpr duration& operator%=(const duration& rhs);(6)(since C++17)
- Demo
std::chrono::duration<int, std::ratio<1, 2>> d1{1};
print("d1", d1);
std::chrono::duration<int, std::ratio<1, 3>> d2{1};
std::chrono::duration<int, std::ratio<1>> d3{1};
// d1 += d2; 不存在從d2 Period 到 d1 Period的隱式轉換
// 通俗的說就是複合賦值的右變量不能是 "短" period
d1 += d3;
print("d1", d1);
- 結果
(d1).count(): 1
(d1).count(): 3
- 說明
- d1 += d2隱式轉換失敗,但是通過duration_cast進行顯式轉換d2後可執行。見下。
- 關於隱式轉換
Implicit conversions between two durations normally depends on the tick period of the durations.
However, implicit conversions can happen regardless of tick period if std::chrono::treat_as_floating_point::value == true- treat_as_floating_point 見下面。
六 非成員函數
1 算術運算
- 兩個duration算術運算(+ - * / %)
- 定義
template< class Rep1, class Period1, class Rep2, class Period2 >
typename std::common_type<duration<Rep1,Period1>, duration<Rep2,Period2>>::type
constexpr operator+( const duration<Rep1,Period1>& lhs,
const duration<Rep2,Period2>& rhs );(1)
template< class Rep1, class Period1, class Rep2, class Period2 >
typename std::common_type<duration<Rep1,Period1>, duration<Rep2,Period2>>::type
constexpr operator-( const duration<Rep1,Period1>& lhs,
const duration<Rep2,Period2>& rhs );(2)
template< class Rep1, class Period, class Rep2 >
duration<typename std::common_type<Rep1,Rep2>::type, Period>
constexpr operator*( const duration<Rep1,Period>& d, const Rep2& s );(3)
template< class Rep1, class Rep2, class Period >
duration<typename std::common_type<Rep1,Rep2>::type, Period>
constexpr operator*( const Rep1& s, const duration<Rep2,Period>& d );(4)
template< class Rep1, class Period, class Rep2 >
duration<typename std::common_type<Rep1,Rep2>::type, Period>
constexpr operator/( const duration<Rep1,Period>& d, const Rep2& s );(5)
template< class Rep1, class Period1, class Rep2, class Period2 >
typename std::common_type<Rep1,Rep2>::type
constexpr operator/( const duration<Rep1,Period1>& lhs,
const duration<Rep2,Period2>& rhs );(6)
template< class Rep1, class Period, class Rep2 >
duration<typename std::common_type<Rep1,Rep2>::type, Period>
constexpr operator%( const duration<Rep1, Period>& d, const Rep2& s );(7)
template< class Rep1, class Period1, class Rep2, class Period2 >
typename std::common_type<duration<Rep1,Period1>, duration<Rep2,Period2>>::type
constexpr operator%( const duration<Rep1,Period1>& lhs,
const duration<Rep2,Period2>& rhs );(8)
- Demo
std::chrono::duration<int, std::ratio<1, 2>> d1{1};
print("d1", d1);
std::chrono::duration<int, std::ratio<1, 3>> d2{1};
print("d1+d2", d1 + d2);
std::cout << "typeid(decltype(d1+d2)).name(): " << std::endl
<< typeid(decltype(d1+d2)).name() << std::endl;
print("d1-d2", d1 - d2);
print("2*d1", 2 * d1);
print("d2*2", d2 * 2);
std::cout << "d1/d2 : " << d1 / d2 << std::endl; // 2
print("d1/2", d1 / 2);
print("d1%d2", d1 % d2);
print("d1%2", d1 % 2);
- 結果
(d1).count(): 1
(d1+d2).count(): 5 // 1
typeid(decltype(d1+d2)).name(): // 1
class std::chrono::duration<int,struct std::ratio<1,6> >
(d1-d2).count(): 1
(2*d1).count(): 2
(d2*2).count(): 2
d1/d2 : 1 // 2
(d1/2).count(): 0
(d1%d2).count(): 1
(d1%2).count(): 1
- 注意
- 注意定義(6),兩個duration相除是一個數值類型(結果2)
- common_type見下面
- 關於結果1
- duration和 的單位是兩個duration單位的最大公因數
- 分數的最大公因數求解步驟:
- 分數轉換爲假分數
- 分子最大公因數/ 分母最小公倍數
- 1/2 和 1/3 的最大公因數 = 1 / (2 * 3) = 1/6
- 5/2 和 10/3 的最大公因數 = 5 / (2 * 3) = 5/6
- 注意定義(6),兩個duration相除是一個數值類型(結果2)
2 關係運算
- 兩個duration關係運算(==,!=,<,<=,>,>=,<=>)
- 定義
template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator==(const std::chrono::duration<Rep1, Period1>& lhs,
const std::chrono::duration<Rep2, Period2>& rhs);(1)(since C++11)
template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator!=(const std::chrono::duration<Rep1, Period1>& lhs,
const std::chrono::duration<Rep2, Period2>& rhs);(2)(since C++11)(until C++20)
template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator<(const std::chrono::duration<Rep1, Period1>& lhs,
const std::chrono::duration<Rep2, Period2>& rhs);(3)(since C++11)
template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator<=(const std::chrono::duration<Rep1, Period1>& lhs,
onst std::chrono::duration<Rep2, Period2>& rhs);(4)(since C++11)
template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator>(const std::chrono::duration<Rep1, Period1>& lhs,
const std::chrono::duration<Rep2, Period2>& rhs);(5)(since C++11)
template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator>=(const std::chrono::duration<Rep1, Period1>& lhs,
const std::chrono::duration<Rep2, Period2>& rhs);(6)(since C++11)
template <class Rep1, class Period1, class Rep2, class Period2>
requires std::three_way_comparable<std::common_type_t<Rep1, Rep2>>
constexpr auto operator<=>(const std::chrono::duration<Rep1, Period1>& lhs,
const std::chrono::duration<Rep2, Period2>& rhs);(7)(since C++20)
- Demo
std::chrono::duration<int, std::ratio<1, 2>> d1{1};
std::chrono::duration<int, std::ratio<1, 3>> d2{1};
std::cout << "d1==d2 : " << (d1==d2) << std::endl;
- 結果
d1==d2 : 0
3 duration_cast
- 顯式轉換duration
- 定義
template <class ToDuration, class Rep, class Period>
constexpr ToDuration duration_cast(const duration<Rep,Period>& d);(C++11 起)
- 說明
- 函數不參與重載決議,除非 ToDuration 是 std::chrono::duration 的實例
- 在源duration能準確地爲目標duration所整除的場合(例如小時到分鐘),浮點時長和整數時長間轉型能隱式進行,無需 duration_cast
- 從浮點時長轉型到整數時長,在浮點值爲 NaN 、無窮大或過大而無法以目標的整數類型表示時,行爲未定義
- Demo
std::chrono::duration<int, std::ratio<1, 3>> d1{1};
auto d2 = std::chrono::duration_cast<std::chrono::duration<int,
std::ratio<1, 10>>>(d1);
print("d2", d2);
- 結果
(d2).count(): 3
4 floor ceil round abs [C++17]
- floor向下取整;ceil向上取整;round就近取整,偶數優先;abs獲取絕對值;
- Demo
std::chrono::duration<int, std::ratio<1, 3>> d1{1};
auto d3 = std::chrono::floor<std::chrono::duration<int,
std::ratio<1, 10>>>(d1);
print("d3", d3);
auto d4 =
std::chrono::ceil<std::chrono::duration<int, std::ratio<1, 10>>>(d1);
print("d4", d4);
auto d5 =
std::chrono::round<std::chrono::duration<int, std::ratio<1, 10>>>(d1);
print("d5", d5);
auto d5_1 =std::chrono::round<std::chrono::duration<int,
std::ratio<1, 5>>>(d5);
print("d5_1", d5_1);
std::chrono::duration<int, std::ratio<1, 3>> d6{-1};
auto d7 = std::chrono::abs(d6);
print("d7", d7);
- 結果
(d3).count(): 3
(d4).count(): 4
(d5).count(): 3 // round 就近取整
(d5_1).count(): 2 // round 偶數優先
(d7).count(): 1
5 operator<< 、from_stream [C++20]
- 略
七 輔助類型
- 定義了一些常用duration類型 (using別名)
std::chrono::nanoseconds;
std::chrono::microseconds;
std::chrono::milliseconds;
std::chrono::seconds;
std::chrono::minutes;
std::chrono::hours;
// C++20
// std::chrono::days
// std::chrono::weeks
// std::chrono::months
// std::chrono::years
- Demo
std::this_thread::sleep_for(std::chrono::seconds(1));
八 輔助類
1 std::common_type
- 確定兩個duration的共用類型(std::common_type 特化)
- Demo
std::chrono::seconds d1(1);
std::chrono::minutes d2(1);
typedef std::common_type<std::chrono::seconds,
std::chrono::minutes>::type type;
std::cout << typeid(type).name() << std::endl;
type d3(d2);
print("d3", d3);
- 結果
class std::chrono::duration<__int64,struct std::ratio<1,1> >
(d3).count(): 60
2 treat_as_floating_point
- 可用於duration轉換判斷
- Demo
auto v = std::chrono::treat_as_floating_point<std::chrono::milliseconds::rep>::value;
3 duration_values
- 定義Rep類型的3個特殊值(3個static方法)
- 定義
template <class Rep>
struct duration_values;(C++11 起)
- Demo
std::cout << std::chrono::duration_values<std::chrono::seconds::rep>::zero()
<< std::endl;
std::cout << std::chrono::duration_values<std::chrono::seconds::rep>::min()
<< std::endl;
std::cout << std::chrono::duration_values<std::chrono::seconds::rep>::max()
<< std::endl;
- 結果
0
-9223372036854775808
9223372036854775807
4 std::formatter [C++20]
- 略
九 字面量 [C++14]
- 定義於內聯命名空間 std::literals::chrono_literals
operator"“h(C++14) 表示小時的 std::chrono::duration 字面量
operator”“min(C++14) 表示分鐘的 std::chrono::duration 字面量
operator”“s (C++14) 表示秒的 std::chrono::duration 字面量
operator”“ms(C++14) 表示毫秒的 std::chrono::duration 字面量
operator”“us(C++14) 表示微秒的 std::chrono::duration 字面量
operator”"ns(C++14) 表示納秒的 std::chrono::duration 字面量
- Demo
// 例子1
using namespace std::chrono_literals;
print("10h", 10h);
// 例子2
std::this_thread::sleep_for(1s);
- 結果
// 例子1
(10h).count(): 10
十 參考
- 《C++ 標準庫 第2版》
- cppreference - duration