You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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的值,现提出两个问题:

  1. end的具体数据类型是什么?为何无法与start使用相同类型?
  2. 如何像打印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_durationduration<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

火山引擎 最新活动