You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无需显式Tm类直接构造std::chrono高分辨率时钟时间点?

嘿,这个需求很有意思!咱们来聊聊怎么实现这种简洁的time_point直接构造,以及你提到的几个思路~

首先得明确核心限制:你没法给标准库的std::chrono::time_point或其关联时钟添加新构造函数,而且编译器不会自动把裸初始化列表{2013,1,2,...}转换成你的自定义Tm类型(因为初始化列表是braced-init-list,没有明确类型,编译器不会触发隐式转换)。所以std::chrono::high_resolution_clock::time_point tp4{{2013, 1,2,10,11,12,-1, 1234}};这种写法确实没法直接生效,但咱们有几个替代方案可以达到类似的简洁性:

方案1:工厂函数(最接近你的原始写法)

既然不能直接扩展time_point,咱们可以写一个轻量的工厂函数,把构造Tm和转换time_point的逻辑封装起来,调用时完全不用显式写Tm:

#include <chrono>
#include <ctime>

// 先保留你的自定义Tm类(假设实现了到time_point的转换)
struct Tm : std::tm {
    Tm(int year, int month, int day, int hour, int min, int sec, int dst, int usec) {
        tm_year = year - 1900; // std::tm年份是1900偏移量
        tm_mon = month - 1;    // 月份从0开始
        tm_mday = day;
        tm_hour = hour;
        tm_min = min;
        tm_sec = sec;
        tm_isdst = dst;
        usec_ = usec;
    }

    operator std::chrono::high_resolution_clock::time_point() const {
        auto tmp_tm = *this; // mktime会修改tm,所以拷贝一份
        auto time_t_val = mktime(&tmp_tm);
        auto sys_tp = std::chrono::system_clock::from_time_t(time_t_val);
        // 转换到high_resolution_clock(处理平台差异)
        auto high_tp = std::chrono::time_point_cast<std::chrono::high_resolution_clock::duration>(sys_tp);
        return high_tp + std::chrono::microseconds(usec_);
    }

private:
    int usec_;
};

// 工厂函数:接收时间参数,内部构造Tm并转换为time_point
auto make_high_res_time_point(int year, int month, int day, int hour, int min, int sec, int dst, int usec) {
    return static_cast<std::chrono::high_resolution_clock::time_point>(
        Tm{year, month, day, hour, min, sec, dst, usec}
    );
}

// 使用方式(和你想要的写法几乎一样,只是多了函数名)
int main() {
    auto tp4 = make_high_res_time_point(2013, 1, 2, 10, 11, 12, -1, 1234);
}

这个方案的优势是完全贴合你的原始需求,代码改动小,调用简洁,而且不需要额外学习新语法。

方案2:用户定义字面量(Howard提到的思路)

字面量的方式可读性更强,而且可以用更自然的语法来表示时间。这里分两种实现思路:

思路A:字符串字面量(推荐,直观不易错)

直接用标准的日期时间字符串加后缀,内部解析成time_point:

#include <chrono>
#include <ctime>
#include <string>
#include <sstream>
#include <iomanip>

// 自定义字面量后缀_tp,解析日期时间字符串为high_resolution_clock::time_point
std::chrono::high_resolution_clock::time_point operator""_tp(const char* str, std::size_t len) {
    std::string time_str(str, len);
    std::tm tm{};
    int usec = 0;
    std::istringstream iss(time_str);

    // 解析日期和时间部分(格式:YYYY-MM-DD HH:MM:SS.uuuuuu)
    iss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
    char dot;
    iss >> dot >> usec;

    // 转换为time_point
    auto tmp_tm = tm;
    auto time_t_val = mktime(&tmp_tm);
    auto sys_tp = std::chrono::system_clock::from_time_t(time_t_val);
    auto high_tp = std::chrono::time_point_cast<std::chrono::high_resolution_clock::duration>(sys_tp);
    return high_tp + std::chrono::microseconds(usec);
}

// 使用方式
int main() {
    auto tp4 = "2013-01-02 10:11:12.001234"_tp;
}

这种写法非常直观,符合日常书写日期时间的习惯,而且可以轻松扩展支持其他格式(比如带时区的字符串)。

思路B:链式字面量(接近你的参数列表风格)

通过重载/运算符,把年份、月份等参数链式组合起来:

#include <chrono>
#include <ctime>

// 辅助结构体,存储日期和时间部分
struct DateComponents { int year; int month; int day; };
struct TimeComponents { int hour; int min; int sec; int usec; int dst; };

// 年份字面量
DateComponents operator""_y(unsigned long long year) {
    return {static_cast<int>(year), 0, 0};
}

// 链式组合月份、日期
DateComponents operator/(DateComponents d, unsigned long long month) {
    d.month = static_cast<int>(month);
    return d;
}
DateComponents operator/(DateComponents d, unsigned long long day) {
    d.day = static_cast<int>(day);
    return d;
}

// 链式组合小时、分钟、秒、微秒
TimeComponents operator/(DateComponents d, unsigned long long hour) {
    return {static_cast<int>(hour), 0, 0, 0, -1}; // 默认dst=-1
}
TimeComponents operator/(TimeComponents t, unsigned long long min) {
    t.min = static_cast<int>(min);
    return t;
}
TimeComponents operator/(TimeComponents t, unsigned long long sec) {
    t.sec = static_cast<int>(sec);
    return t;
}
TimeComponents operator/(TimeComponents t, unsigned long long usec) {
    t.usec = static_cast<int>(usec);
    return t;
}

// 最终转换为time_point
std::chrono::high_resolution_clock::time_point operator/(DateComponents d, TimeComponents t) {
    Tm tm{d.year, d.month, d.day, t.hour, t.min, t.sec, t.dst, t.usec};
    return static_cast<std::chrono::high_resolution_clock::time_point>(tm);
}

// 使用方式
int main() {
    auto tp4 = 2013_y / 1 / 2 / 10 / 11 / 12 / 1234;
}

这种写法完全模拟了你想要的参数列表风格,通过字面量和运算符重载实现了“自然语言”式的时间构造。

关于用户定义推导指引的补充

你提到的推导指引其实不太适用这里:推导指引是用来帮助编译器推导模板类的模板参数的,而std::chrono::high_resolution_clock::time_point的模板参数(时钟、duration)都是固定的,推导指引没法帮你添加新的构造逻辑。所以推导指引并不能让time_point{2013,1,2,...}生效,还是得靠上面的工厂函数或字面量方案。


内容的提问来源于stack exchange,提问作者Klaus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:06:03