为何调整std::chrono::floor的调用顺序会引发C++编译错误?
解析:chrono中floor调用顺序导致的编译错误原因
我使用g++ 14.2.1(启用-std=gnu++20)编译chrono相关代码时,遇到了因floor调用顺序不同导致的编译错误,以下是具体情况及原因分析:
可正常运行的写法
year_month_day day() { return year_month_day(floor<days>( zoned_time{ zone, system_clock::now() }.get_local_time())); }
触发编译错误的写法
year_month_day day2() { return year_month_day( zoned_time{ zone, floor<days>(system_clock::now()) }.get_local_time()); }
错误信息
error: no matching function for call to ‘std::chrono::year_month_day::year_month_day(std::chrono::local_time<std::chrono::duration<long int> >)’ 48 | }.get_local_time());
核心原因分析
两种写法的本质差异在于**floor<days>作用的对象类型不同**,最终导致get_local_time()返回的local_time精度类型与year_month_day构造函数的要求不匹配:
第一种写法的执行流程
system_clock::now()返回高精度的sys_time<nanoseconds>(系统时间轴上的纳秒级时间点)。- 构造
zoned_time后调用get_local_time(),得到对应时区的local_time<nanoseconds>。 - 对
local_time<nanoseconds>执行floor<days>,得到标准的local_time<days>(即local_days,代表本地时间轴上某一天的起始时刻)。 year_month_day的构造函数支持直接从local_days转换,因此可以正常编译。
第二种写法的执行流程
- 先对
system_clock::now()执行floor<days>,得到sys_time<days>(系统时间轴上某一天的起始时刻)。 - 用这个
sys_time<days>构造zoned_time后,get_local_time()返回的是local_time<duration<long int, ratio<86400>>>——这个类型与标准local_days(local_time<days>,其中days是duration<intmax_t, ratio<86400>>的typedef)的模板参数类型不一致。 year_month_day的构造函数无法匹配这个非标准的local_time类型,因此触发编译错误。
- 先对
修复方案
如果想要保留第二种写法的逻辑(先取系统时间的天再转本地时间),可以显式将get_local_time()的结果转换为local_days:
year_month_day day2() { return year_month_day( local_days{ zoned_time{ zone, floor<days>(system_clock::now()) }.get_local_time() }); }
注意:两种写法的业务逻辑存在差异——第一种是先将当前系统时间转换为本地时间再取天,第二种是先取系统时间的天再转换为本地时间,在跨时区的午夜时刻可能得到不同的日期结果,需要根据实际需求选择。
内容的提问来源于stack exchange,提问作者John Graham
相关产品推荐
相关产品推荐

