chrono_duration(一)
文章目录
- chrono简介
- std::chrono::duration
- duratio基本介绍
- 基本概念
- 使用引入
- std::ratio 参数深入
- 特化的duratio
- 改造之前的代码
- 静态成员函数 count
- 原型
- 例子
- 构造函数
- 支持加减乘除运算
- 编译细节
- 支持比较运算符
- 查询范围
- 类型转换
- 例子引入
- 修改seconds的范围
- 浮点类型
- 系统特化的duratio
- 自定义单位转换
- duratio源码补充
- radio 源码补充
- duration_cast()分析
- 例子(重要)
- 预定义的 radio
- 改写例子中的代码
- 改写例子中的代码
chrono简介
chrono
是一个基于模板的,面向对象的,设计优雅且功能强大的time library。chrono
内部定义了三种和时间相关的类型:
- duration:一个duration就代表了一个时间段,比如2分钟,4小时等等。
- clock: clock的作用就相当于我们日常使用的手表:显示时间。
chrono
内部定义了三种clock:system clock
、steady clock
和high-resolution-clock
。 - time point:time point表示某个特定的时间点。
std::chrono::duration
duratio基本介绍
基本概念
template<class Rep,class Period = std::ratio<1>
> class duration;
类模板 std::chrono::duration
表示时间间隔。
它由 Rep
类型的计次数和计次周期组成,其中计次周期是一个编译期有理数常量,表示从一个计次到下一个的秒数。
存储于 duration
的数据仅有 Rep
类型的计次数。若 Rep
是浮点数,则 duration
能表示小数的计次数。 Period
被包含为时长类型的一部分,且只在不同时长间转换时使用。
使用引入
例子:用 chorono 库 刻画 5s 的时间间隔
std::chrono::duration<float, std::ratio<2 / 1>> Five_Second = std::chrono::duration<float, ratio<2 / 1>>(2.5);
这里的Rep (计次数类型)
就是float
, 这里的计次数
就是 2.5
, 这里的 计次周期
就是 2/1 =2 s
时间间隔 = 计次数(2.5)
* 计次周期(2)
=5s
- 它所表示的时间间隔和下面是等价的
std::chrono::duration<int, std::ratio<5 / 1>> Five_Second = std::chrono::duration<int, ratio<5 / 1>>(1);
这里的Rep (计次数类型)
就是int
, 这里的计次数
就是 1
, 这里的 计次周期
就是 5/1 =5 s
时间间隔 = 计次数(1)
* 计次周期(5)
=5s
std::ratio 参数深入
duration
的声明包含两个模板参数,第一个模板参数是C++的原生数值类型,如long
, long long
等,代表了duration
的数值部分。第二个模板参数_Period
又是一个模板类std::ratio
,它的定义如下:
template<std::intmax_t Num,std::intmax_t Denom = 1
> class ratio;
// file: rationamespace chrono {// ratio以模板的方式定义了有理数,比如ratio<1,60>就表示有理数 ‘1/60’// _Num代表 'numerator'(分子)// _Den代表 'denominator'(分母)template<intmax_t _Num, intmax_t _Den = 1>class ration {// 求__Num的绝对值static constexpr const intmax_t __na = __static_abs<_Num>::value;// 求_Den的绝对值static constexpr const intmax_t __da = __static_abs<_Den>::value;// __static_sign的作用是求符号运算static constexpr const intmax_t __s = __static_sign<_Num>::value * __static_sign<_Den>::value;// 求分子、分母的最大公约数static constexpr const intmax_t __gcd = __static_gcd<__na, __da>::value;public:// num是化简后的_Numstatic constexpr const intmax_t num = __s * __na / __gcd;// den是化简后的_Denstatic constexpr const intmax_t den = __da / __gcd;};
}
ratio
用两个整数型模板参数来表示一个有理数的分子和分母部分,比如ratio<1, 1000>
就表示有理数0.001
。理解了这一点,我们再来看duration
的定义:
template<class _Rep, class _Period = ratio<1> > class duration
ratio
在这里的确切含义为:以秒为单位的放大倍率,比如ratio<60, 1>
表示一个1秒的60倍,也就是1分钟
,而ratio<1, 1000>
表示1秒的千分之一倍,也就是1毫秒
。所以duration<long, ratio<60, 1>>
就定义了一个类型为long
的duration
,而这个duration
的单位为“分钟”。
特化的duratio
chrono中宏定义了许多特例化了的duration:
就是常见的hours,miniutes,seconds,milliseconds等,使用std::chrono::milliseconds直接使用
namespace chrono {// 1nano = 1/1,000,000,000 秒typedef ratio<1LL, 1000000000LL> nano;// 1micro = 1/1,000,000秒typedef ratio<1LL, 1000000LL> micro;// 1milli = 1/1,000秒typedef ratio<1LL, 1000LL> milli;// 1centi = 1/100秒typedef ratio<1LL, 100LL> centi;// 1kilo = 1,000秒typedef ratio<1000LL, 1LL> kilo;// 1mega = 1,000,000秒typedef ratio<1000000LL, 1LL> mega;// ...typedef duration<long long, nano> nanoseconds; // nanosecond是duration对象 ,nano 是 ratio对象typedef duration<long long, micro> microseconds;typedef duration<long long, milli> milliseconds;typedef duration<long long > seconds;typedef duration< long, ratio< 60> > minutes;typedef duration< long, ratio<3600> > hours;// ...
}
改造之前的代码
例子:用 chorono 库 刻画 5s 的时间间隔
std::chrono::seconds Five_Second = std::chrono::seconds(5); // 这里的seconds 就是 特化的duration
静态成员函数 count
原型
constexpr rep count() const;
std::chrono::duration<Rep,Period>::count
- 返回值
此 duration 的计次数。
例子
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;
int main(int argc, char **argv)
{std::chrono::seconds Five_Second = std::chrono::seconds(5);cout << "Five_seconds的计次数为:: " << Five_Second.count() << endl;
}
Five_seconds的计次数为:: 5
构造函数
void func(std::chrono::seconds d)
{cout << "d的计次数为:: " << d.count() << endl;
}int main(int argc, char **argv)
{// std::chrono::seconds Five_Second = std::chrono::seconds(5);// cout << "Five_seconds的计次数为:: " << Five_Second.count() << endl;// todo1 构造函数std::chrono::seconds Five_Second1; // 未初始化std::chrono::seconds Five_Second2{}; // 零初始化std::chrono::seconds Five_Second3{5}; // ok 5sstd::chrono::seconds Five_Second3(5s); // ok 5s// todo2 不允许隐式类型转换// std::chrono::seconds Five_Second3 = 5; // error 不允许隐式类型转换// func(5); // error 不允许隐式类型转换func(5s); // ok 5s
}
支持加减乘除运算
void func(std::chrono::seconds d){cout << "d的计次数为:: " << d.count() << endl;}void func2(){auto x = 3s;x += 2s;func(x);x = x - 5s;// x+=5;//error 不能加 int func(x);}// d的计次数为::5 d的计次数为::0
编译细节
比较编译器所花费时间
- code1
std::chrono::seconds func(std::chrono::seconds d1,std::chrono::seconds d2)
{return d1+d2;
}
- code 2
int64_t func(int64_t x1,int64_t x2)
{return x1+x2;
}
实际上他们的汇编代码是相同的,除了顶部名称修改
不仅仅局限在此,下面代码的运算也是相同的
支持比较运算符
namespace detail2
{constexpr auto time_limit = 5s;void fun(std::chrono::seconds s){if (s == time_limit){cout << "equal time" << endl;}else if (s <= time_limit){cout << "in time" << endl;}else{cout << "out of time" << endl;}}
}detail2::fun(1s);detail2::fun(5s);detail2::fun(6s);
in time
equal time
out of time
查询范围
auto max = std::chrono::seconds::max();auto min = std::chrono::seconds::min();cout << "max = " << max.count() << endl;cout << "min = " << max.count() << endl;
类型转换
例子引入
- 一般来说: 如果一个 < chrono > 转换是无损的,那么它是隐式的。如果一个转换不是无损的,它不会在没有特殊语法的情况下编译。
- 如果转换会带来精度损失,编译就会报错。如果一定需要这样的转换,就要进行explicitly(明确的)的转换
namespace detail
{void func(){auto time_day = 24h;auto time_seconds = std::chrono::seconds(time_day);cout << time_seconds.count() << endl;}// void func2()// {// auto time_seconds = 86400s;// auto time_day = std::chrono::hours(time_seconds);// // chrono 库不支持 将 duration(持续时间)类型从更精确的类型转换为不太精确的类型// cout << time_day.count() << endl;// }void func3(){auto time_seconds = 86400s;auto time_day = std::chrono::duration_cast<std::chrono::hours>(time_seconds);cout << time_day.count() << endl;}void func4(){auto mi = std::chrono::milliseconds{3400ms};std::chrono::seconds s = std::chrono::duration_cast<std::chrono::seconds>(mi);cout << s.count() << endl;}}
int main(int argc, char **argv)
{// 初步认识 duration_cast()强制转换detail::func(); // 这里没有损失精度// detail::func2(); // errordetail::func3(); // 这里没有损失精度+detail::func4(); //输出 3 s ,损失精度}
修改seconds的范围
- 如果觉得64bit表示seconds太浪费,
<chrono>
还提供下面的方法,依然可以像上面的那些duration那样互转。
using seconds32 = std::chrono::duration<int32_t>;
- 甚至下面这个也能工作:
using seconds32 = std::chrono::duration<uint32_t>;
- 甚至下面这个也能工作(使用“safeint”库):
using seconds32 = std::chrono::duration<safe<uint32_t>>;
- 甚至下面这个也能工作(使用浮点类型):
using fseconds = std::chrono::duration<float>;
浮点类型
对于浮点表示形式,可以从任何精度进行隐式转换,而不需要使用 period _ cast。其基本原理是没有截尾误差(只有舍入误差)。所以隐式转换是安全的。
原始的毫秒
typedef ratio<1LL, 1000LL> milli;
using my_ms = std::chrono::duration<double, std::milli>; // double 也可以用float代替void myf(my_ms d){cout << "my_ms:: " << d.count() << " ms\n";};void f(std::chrono::milliseconds d){cout << "f::" << d.count() << " ms\n";};void func(){// f(45ms + 63us);//原始的毫秒不支持隐式类型转换myf(45ms + 63us); // 45.063 ms}
系统特化的duratio
typedef ratio<1LL, 1000000000LL> nano;// 1micro = 1/1,000,000秒typedef ratio<1LL, 1000000LL> micro;// 1milli = 1/1,000秒typedef ratio<1LL, 1000LL> milli;// 1centi = 1/100秒typedef ratio<1LL, 100LL> centi;// 1kilo = 1,000秒typedef ratio<1000LL, 1LL> kilo;// 1mega = 1,000,000秒typedef ratio<1000000LL, 1LL> mega;
typedef duration<long long, nano> nanoseconds; // 纳秒
typedef duration<long long, micro> microseconds; // 微秒
typedef duration<long long, milli> milliseconds; // 毫秒
typedef duration<long long> seconds; // 秒
typedef duration<int, ratio<60> > minutes; // 分钟
typedef duration<int, ratio<3600> > hours; // 小时
自定义单位转换
#include <iostream>
#include <chrono> typedef std::chrono::duration<float, std::ratio<3, 1> > three_seconds;
typedef std::chrono::duration<float, std::ratio<1, 10> > one_tenth_seconds; int main()
{ three_seconds s = std::chrono::duration_cast<three_seconds>(one_tenth_seconds(3)); std::cout << "3 [1/10 seconds] equal to " << s.count() << " [3 seconds]\n"; std::cin.get();
}
duratio源码补充
std::chrono::duration是一个模板类,关键代码摘录如下(格式有调整):
template<class _Rep, class _Period>
class duration {
public: typedef duration<_Rep, _Period> _Myt; typedef _Rep rep; typedef _Period period; // constructor, save param to _MyRep, used by count() member function. template<class _Rep2, class = typename enable_if<is_convertible<_Rep2, _Rep>::value && (treat_as_floating_point<_Rep>::value || !treat_as_floating_point<_Rep2>::value), void>::type> constexpr explicit duration(const _Rep2& _Val) : _MyRep(static_cast<_Rep>(_Val)) { } constexpr _Rep count() const { return (_MyRep); }
}; // convert duration from one unit to another.
template<class _To, class _Rep, class _Period> inline
constexpr typename enable_if<_Is_duration<_To>::value, _To>::type
duration_cast(const duration<_Rep, _Period>& _Dur)
{
typedef ratio_divide<_Period, typename _To::period> _CF; typedef typename _To::rep _ToRep;
typedef typename common_type<_ToRep, _Rep, intmax_t>::type _CR; #pragma warning(push)
#pragma warning(disable: 6326) // Potential comparison of a constant with another constant.
return (_CF::num == 1 && _CF::den == 1 ? static_cast<_To>(static_cast<_ToRep>(_Dur.count())) : _CF::num != 1 && _CF::den == 1 ? static_cast<_To>(static_cast<_ToRep>( static_cast<_CR>( _Dur.count()) * static_cast<_CR>(_CF::num))) : _CF::num == 1 && _CF::den != 1 ? static_cast<_To>(static_cast<_ToRep>( static_cast<_CR>(_Dur.count()) / static_cast<_CR>(_CF::den))) : static_cast<_To>(static_cast<_ToRep>( static_cast<_CR>(_Dur.count()) * static_cast<_CR>(_CF::num) / static_cast<_CR>(_CF::den))));
#pragma warning(pop)
}
radio 源码补充
std::ratio是一个模板类,关键代码摘录如下(格式有调整):
template<intmax_t _Nx, intmax_t _Dx = 1>
struct ratio
{ static_assert(_Dx != 0, "zero denominator"); static_assert(-INTMAX_MAX <= _Nx, "numerator too negative"); static_assert(-INTMAX_MAX <= _Dx, "denominator too negative"); static constexpr intmax_t num = _Sign_of<_Nx>::value * _Sign_of<_Dx>::value * _Abs<_Nx>::value / _Gcd<_Nx, _Dx>::value; static constexpr intmax_t den = _Abs<_Dx>::value / _Gcd<_Nx, _Dx>::value; typedef ratio<num, den> type;
};
第一个参数_Nx
代表了分子,第二个参数 _Dx
代表了分母。
num
是计算后的分子,den
是计算后的分母。在duration转换的时候会用到这两个值。
注:这里的计算是指约分,可以看到传入的分子和分母都除以了最大公约数。
num
是numerator
的缩写,表示分子。
den
是denominator
的缩写,表示分母。
duration_cast()分析
- 注明:这个函数是在duration 源码中的
函数duration_cast()
提供了在不同的时间单位之间进行转换的功能。
duration_cast()
主要分为两部分:
- 通过
ratio_divide
定义了从一个ratio转换到另外一个ratio的转换比例。
比如1/10
到2/5
的转换比例是1/4
((1/10/(2/5)) = 1/4),也就是说一个1/10
相当于1/4
个2/5
。
对应到代码里就是_CF::num = 1, _CF::den = 4
. - 根据转换比例把n个单位的原数据转换到目标数据(return语句)
return
语句写的这么复杂是为了效率,避免不必要的乘除法,当分子是1的时候没必要乘,当分母是1的时候没必要除。
简化一下(去掉了强制类型转换)就是:
return _Dur.count() * (_CF::num / _CF::den);
通俗点讲:如果A
到B
的转换比例是num/den
,那么1
个A
可以转换为num/den
个B
, n
个A
可以转换为 n * (num/den)
个B
。
例子(重要)
#include <iostream>
#include <chrono>
int main()
{ std::chrono::milliseconds mscond(1000); // 1 second std::cout << mscond.count() << " milliseconds.\n"; //1000// 时间间隔 = `计次数(count)` * `计次周期(ration)` std::cout << mscond.count() * std::chrono::milliseconds::period::num / std::chrono::milliseconds::period::den; // 1000* 1/1000std::cout << " seconds.\n"; system("pause"); return 0;
}
这里的需要注意的是 std::chrono::milliseconds::period::num
和 std::chrono::milliseconds::period::den
拆开来理解:
std::chrono::milliseconds
是 duration 模板类的特化,也就是 duration类
, 在duration 类 的成员中有如下成员:
typedef duration<_Rep, _Period> _Myt; typedef _Rep rep; typedef _Period period;
所以 std::chrono::milliseconds::period
就是 引用duration中的 period成员, 接着看下面duration的类模版声明
template< class Rep,class Period = std::ratio<1>
> class duration;
其中 period 是 _Period 类型的 ,也就是 ratio<> 类型的;所以 period 就相当于 是 ratio 类型对象 ,再结合一下ratio源码
中存在两个成员 num 和 den .
就不难得出std::chrono::milliseconds::period::num
/ std::chrono::milliseconds::period::den
是 milliseconds (duration)的 ratio
(计数周期) 也就是 1/1000 【关键】
注:ratio 源码(部分)
static constexpr intmax_t num = _Sign_of<_Nx>::value * _Sign_of<_Dx>::value * _Abs<_Nx>::value / _Gcd<_Nx, _Dx>::value; static constexpr intmax_t den = _Abs<_Dx>::value / _Gcd<_Nx, _Dx>::value; typedef ratio<num, den> type;
预定义的 radio
为了方便代码的书写,标准库提供了如下定义:
Type | Definition |
---|---|
yocto | std::ratio<1, 1000000000000000000000000>, if std::intmax_t can represent the denominator |
zepto | std::ratio<1, 1000000000000000000000>, if std::intmax_t can represent the denominator |
atto | std::ratio<1, 1000000000000000000> |
femto | std::ratio<1, 1000000000000000> |
pico | std::ratio<1, 1000000000000> |
nano | std::ratio<1, 1000000000> |
micro | std::ratio<1, 1000000> |
milli | std::ratio<1, 1000> |
centi | std::ratio<1, 100> |
deci | std::ratio<1, 10> |
deca | std::ratio<10, 1> |
hecto | std::ratio<100, 1> |
kilo | std::ratio<1000, 1> |
mega | std::ratio<1000000, 1> |
giga | std::ratio<1000000000, 1> |
tera | std::ratio<1000000000000, 1> |
peta | std::ratio<1000000000000000, 1> |
exa | std::ratio<1000000000000000000, 1> |
zetta | std::ratio<1000000000000000000000, 1>, if std::intmax_t can represent the numerator |
yotta | std::ratio<1000000000000000000000000, 1>, if std::intmax_t can represent the numerator |
改写例子中的代码
结合预定义的radio
#include <iostream>
#include <chrono>
using namespace std;
int main()
{std::chrono::milliseconds mscond(1000); // 1000msstd::cout << mscond.count() << " milliseconds.\n"; // 1000// 时间间隔 = `计次数(count)` * `计次周期(ration)`std::milli mi;std::cout << mscond.count() * mi.num / mi.den; // 1000* 1/1000// cout << "mi.num" << mi.num << "mi.den" << mi.den << endl;std::cout<< " seconds.\n";return 0;
}
|
| zetta | std::ratio<1000000000000000000000, 1>, if std::intmax_t can represent the numerator |
| yotta | std::ratio<1000000000000000000000000, 1>, if std::intmax_t can represent the numerator |
改写例子中的代码
结合预定义的radio
#include <iostream>
#include <chrono>
using namespace std;
int main()
{std::chrono::milliseconds mscond(1000); // 1000msstd::cout << mscond.count() << " milliseconds.\n"; // 1000// 时间间隔 = `计次数(count)` * `计次周期(ration)`std::milli mi;std::cout << mscond.count() * mi.num / mi.den; // 1000* 1/1000// cout << "mi.num" << mi.num << "mi.den" << mi.den << endl;std::cout<< " seconds.\n";return 0;
}
chrono_duration(一)相关推荐
- C++时间库chrono_duration(一)
文章目录 chrono简介 std::chrono::duration duratio基本介绍 基本概念 使用引入 std::ratio 参数深入 特化的duratio 改造之前的代码 静态成员函数 ...
- go+gSoap+onvif学习总结:7、进行镜头调焦、聚焦和预置点的增删改查
cgo+gSoap+onvif学习总结:7.进行镜头调焦.聚焦和预置点的增删改查 文章目录 cgo+gSoap+onvif学习总结:7.进行镜头调焦.聚焦和预置点的增删改查 1. 前言 2. gSoa ...
- Linux gsoap生成onvif框架(C语言客户端代码)一
创作人QQ:851301776,邮箱:lfr890207@163.com,欢迎大家一起技术交流,本博客主要是自己学习的心得体会,只为每天进步一点点! 个人座右铭: 1.没有横空出世,只要厚积一定发. ...
- cgo+gSoap+onvif学习总结:5、获取profileToken、rtsp流地址、快照地址及cgo程序signal SIGSEGV: segmentation violation解决方法
cgo+gSoap+onvif学习总结:5.获取profileToken.rtsp流地址.快照地址及cgo偶发signal SIGSEGV: segmentation violation分割违例解决方 ...
- 浏览器播放rtsp视频流:3、rtsp转webrtc播放
浏览器播放rtsp视频流:3.rtsp转webrtc播放 文章目录 浏览器播放rtsp视频流:3.rtsp转webrtc播放 1. 前言 2. rtsp转webRTC 3. 初步测试结果 4. 结合我 ...
- cgo+gSoap+onvif学习总结:6、进行PTZ控制
cgo+gSoap+onvif学习总结:6.进行PTZ控制 文章目录 cgo+gSoap+onvif学习总结:6.进行PTZ控制 1. 前言 2. gSoap生成c代码框架 3. 实现c代码实例并运行 ...
最新文章
- python 导入自定义模块
- 培养你的核心竞争能力
- Dart 异步编程之 Isolate 和事件循环
- Zookeeper集群角色分配原理
- unubtu16.04解决etc文件误改导致无法使用sudo等指令问题
- 遇见未来 | 对话王璞:谈分布式系统在企业落地的挑战
- 技术人,其实很有优势
- solr 配置中文分析器/定义业务域/配置DataImport功能(测试用)
- Android Studio中修改APP图标和APP名称
- oracle rac 12514,ORA-12514: 错误解决一例
- unity 3d 仿真_在Unity3D中构建3D仿真入门,第1部分
- java毕业设计中国民航酒店分销系统Mybatis+系统+数据库+调试部署
- 酷睿是图拉丁的孙子[经典理论]
- delphi 注册列表的学习
- 從turtle海龜動畫 學習 Python - 高中彈性課程系列 3 烏龜繪圖 所需之Python基礎
- 一二线城市知名IT互联网公司名单,看看你身边
- CSS设置元素的透明度(不透明度)
- 判断给出的秒数是几天几小时几分几秒
- 如何搜索和阅读一篇论文及鉴别论文好坏
- Android加密之全盘加密详解
热门文章
- Linux下gcc/g++中-I(i的大写)、-L和-l
- java毕业设计_企业销售合同管理系统
- 由递推关系式用差分方程的方法得到通项公式实现求斐波那契数列的第n项;迭代、递归、栈、差分方程之间的本质联系以及由推广的迭代法解决“变态青蛙跳台阶”问题;汉诺塔问题的数字特征以及用递归解决的原理推导。
- php根据当前日期判断法定节假日_PHP 判断当前日期是否是法定节假日或者休息日 (原)...
- 深度学习 神经网络 神经元 单层神经网络的实现
- bmi计算器HTML,身高180cm体重110.5kg的男性标准体重与BMI指数 - BMI计算器
- Python3实现斐波那契数列.md
- 传奇怎么设置不显示服务器,如何将传奇服务器未知神殿地图修改为不限制进出...
- C#毕设asp.net江山旅游网站管理系统(论文+源码)
- C#语法基础05_switch