C++11 std::duration

一 chrono庫

  • C++ 標準庫chrono中有三個比較重要的概念,它們分別是:
    • clocks
    • time points
    • durations
  • 本文主要對 duration 概念進行討論。

二 duration

  1. 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.

  1. 定義於頭文件 < 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
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

十 參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章