C++使用chrono库实现定时器的类型匹配及打印问题
C++ 定时器实现的两个问题
我尝试使用C++的<chrono>库实现一个简单定时器,编写的代码如下:
#include <iostream> #include <chrono> int main() { double timer; std::chrono::time_point <std::chrono::system_clock> start; // LINE 1 std::cout << "Enter the duration of timer in seconds: "; std::cin >> timer; std::chrono::duration <double> timer_duration (timer); while (std::cin.get() != '\n'); std::cin.clear(); std::cout << "Press ENTER to start timer"; while (std::cin.get() != '\n'); start = std::chrono::system_clock::now(); std::cout << "Timer started at " << start << std::endl; // LINE 2 auto end = start + timer_duration; // LINE 3 while (std::chrono::system_clock::now() < end); std::cout << "Timer ended at " << std::chrono::system_clock::now() << std::endl; //LINE 4 return 0; }
若将LINE3的end声明为与LINE1的start相同的std::chrono::time_point<std::chrono::system_clock>类型(而非auto),会出现如下编译错误:
error: no match for 'operator=' (operand types are 'std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >' and 'std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<double, std::ratio<1, 1000000000> > >') 20 | end = start + timer_duration; // LINE 3 | ^~~~~~~~~~~~~~ • there are 2 candidates In file included from /cefs/32/3279f7e93638effd41d1c096_gcc-trunk-20260513/include/c++/17.0.0/chrono:51, from <source>:2: • candidate 1: 'constexpr std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >& std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >::operator=(const std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >&)' /cefs/32/3279f7e93638effd41d1c096_gcc-trunk-20260513/include/c++/17.0.0/bits/chrono.h:930:13: 930 | class time_point | ^~~~~~~~~~ • no known conversion for argument 1 from 'std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<double, std::ratio<1, 1000000000> > >' to 'const std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >&' • candidate 2: 'constexpr std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >& std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >::operator=(std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >&&)' • no known conversion for argument 1 from 'std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<double, std::ratio<1, 1000000000> > >' to 'std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >&&'
同时,无法像打印start那样直接打印end的值,现提出两个问题:
end的具体数据类型是什么?为何无法与start使用相同类型?- 如何像打印
start一样打印end的值?
问题解答
1. end的类型及类型不兼容原因
end的具体类型是std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<double, std::ratio<1, 1000000000>>>,简单来说就是基于浮点类型duration的system_clock时间点。- 类型不兼容的核心原因:
std::chrono::system_clock的默认duration是整数类型(通常是std::chrono::nanoseconds,即duration<long long, std::nano>),所以start的类型是基于整数duration的time_point。而你定义的timer_duration是duration<double>(浮点类型的duration),当整数duration的time_point加上浮点duration时,为了保留精度,结果会自动升级为浮点duration的time_point。两种time_point的底层duration类型不同(一个整数、一个浮点),属于不同的模板实例,因此无法直接赋值。
2. 打印end的方法
标准库仅为system_clock默认的整数duration time_point提供了流输出支持,要打印浮点duration的end,可以用以下几种方式:
方法1:转换为system_clock默认类型(损失浮点精度)
将end转换回system_clock的默认time_point类型,即可直接用流输出:
std::cout << "Timer ended at " << std::chrono::system_clock::time_point(end) << std::endl;
注意:这种方式会把浮点精度的时间截断为整数duration,比如原本的1.5秒会被转为1秒。
方法2:提取时间戳后格式化输出
直接提取end的时间戳,转换为易读的格式:
// 输出秒级时间戳(整数) auto end_sec = std::chrono::duration_cast<std::chrono::seconds>(end.time_since_epoch()).count(); std::cout << "Timer ended at: " << end_sec << "s since epoch" << std::endl; // 输出带小数的秒级时间戳(浮点) double end_total_sec = std::chrono::duration<double>(end.time_since_epoch()).count(); std::cout << "Timer ended at: " << end_total_sec << "s since epoch" << std::endl;
方法3:自定义流输出运算符
手动实现针对浮点duration time_point的operator<<,让它支持直接打印:
#include <iomanip> // 需要包含这个头文件来使用setw、setfill template<typename Clock, typename Duration> std::ostream& operator<<(std::ostream& os, const std::chrono::time_point<Clock, Duration>& tp) { // 拆分秒和纳秒部分 auto secs = std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch()); auto nanos = std::chrono::duration_cast<std::chrono::nanoseconds>(tp.time_since_epoch() - secs); // 格式化输出,保证纳秒部分是9位 os << secs.count() << "." << std::setw(9) << std::setfill('0') << nanos.count(); return os; }
之后就可以像打印start一样直接打印end:
std::cout << "Timer ended at " << end << std::endl;
内容的提问来源于stack exchange,提问作者Vinayak Deshmukh




