From c70faa8d6b7ea7d105d71a7dc178edc92b722257 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 24 Nov 2025 05:49:29 -0800 Subject: [PATCH 1/3] Move ref within `type_identity_t` for consistency. --- stl/inc/chrono | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index deed0e8b51f..3d648ada1c3 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -2498,7 +2498,7 @@ namespace chrono { enable_if_t&>, int> = 0> - zoned_time(string_view _Name, type_identity_t>& _Local) + zoned_time(string_view _Name, type_identity_t&> _Local) : zoned_time{_Traits::locate_zone(_Name), _Local} {} template Date: Mon, 24 Nov 2025 05:08:41 -0800 Subject: [PATCH 2/3] zoned_time overhaul: Convert SFINAE to concepts. I'm phrasing the constraints slightly differently from the Standard to perma-workaround EDG bugs, but I believe they're morally equivalent, and in practice everyone uses `const time_zone*` anyways. --- stl/inc/chrono | 84 ++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index 3d648ada1c3..aa3376966c0 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -2460,85 +2460,87 @@ namespace chrono { public: using duration = common_type_t<_Duration, seconds>; - template > - zoned_time() : _Zone{_Traits::default_zone()} {} + zoned_time() + requires requires { _Traits::default_zone(); } + : _Zone{_Traits::default_zone()} {} + zoned_time(const zoned_time&) = default; zoned_time& operator=(const zoned_time&) = default; - template > - zoned_time(const sys_time<_Duration>& _Sys) : _Zone{_Traits::default_zone()}, _Tp{_Sys} {} + zoned_time(const sys_time<_Duration>& _Sys) + requires requires { _Traits::default_zone(); } + : _Zone{_Traits::default_zone()}, _Tp{_Sys} {} explicit zoned_time(_TimeZonePtr _Tz) noexcept /* strengthened */ : _Zone{_STD move(_Tz)} {} - template , int> = 0> - explicit zoned_time(string_view _Name) : _Zone{_Traits::locate_zone(_Name)} {} + explicit zoned_time(string_view _Name) + requires requires { + { _Traits::locate_zone(_Name) } -> convertible_to<_TimeZonePtr>; + } + : _Zone{_Traits::locate_zone(_Name)} {} - template , sys_time<_Duration>>, int> = 0> + template + requires is_convertible_v, sys_time<_Duration>> zoned_time(const zoned_time<_Duration2, _TimeZonePtr>& _Zt) noexcept /* strengthened */ : _Zone{_Zt.get_time_zone()}, _Tp{_Zt.get_sys_time()} {} zoned_time(_TimeZonePtr _Tz, const sys_time<_Duration>& _Sys) : _Zone{_STD move(_Tz)}, _Tp{_Sys} {} - template &>, - int> = 0> zoned_time(string_view _Name, type_identity_t&> _Sys) + requires requires { + { _Traits::locate_zone(_Name) } -> convertible_to<_TimeZonePtr>; + } : zoned_time{_Traits::locate_zone(_Name), _Sys} {} - template ()->to_sys(local_time<_Duration>{})), sys_time>, - int> = 0> zoned_time(_TimeZonePtr _Tz, const local_time<_Duration>& _Local) + requires requires { + { _Tz->to_sys(_Local) } -> convertible_to>; + } : _Zone{_STD move(_Tz)}, _Tp{_Zone->to_sys(_Local)} {} - template &>, - int> = 0> zoned_time(string_view _Name, type_identity_t&> _Local) + requires requires { + { _Traits::locate_zone(_Name) } -> convertible_to<_TimeZonePtr>; + { _STD declval<_TimeZonePtr&>() -> to_sys(_Local) } -> convertible_to>; + } : zoned_time{_Traits::locate_zone(_Name), _Local} {} - template ()->to_sys(local_time<_Duration>{}, choose::earliest)), - sys_time>, - int> = 0> zoned_time(_TimeZonePtr _Tz, const local_time<_Duration>& _Local, choose _Choose) + requires requires { + { _Tz->to_sys(_Local, _Choose) } -> convertible_to>; + } : _Zone{_STD move(_Tz)}, _Tp{_Zone->to_sys(_Local, _Choose)} {} - template &, choose>, - int> = 0> zoned_time(string_view _Name, type_identity_t&> _Local, choose _Choose) + requires requires { + { _Traits::locate_zone(_Name) } -> convertible_to<_TimeZonePtr>; + { _STD declval<_TimeZonePtr&>() -> to_sys(_Local, _Choose) } -> convertible_to>; + } : zoned_time{_Traits::locate_zone(_Name), _Local, _Choose} {} - template , sys_time<_Duration>>, int> = 0> + template + requires is_convertible_v, sys_time<_Duration>> zoned_time(_TimeZonePtr _Tz, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt) noexcept /* strengthened */ : _Zone{_STD move(_Tz)}, _Tp{_Zt.get_sys_time()} {} - template , sys_time<_Duration>>, int> = 0> + template + requires is_convertible_v, sys_time<_Duration>> zoned_time( _TimeZonePtr _Tz, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt, choose) noexcept /* strengthened */ : zoned_time{_Tz, _Zt} {} - template &>, - int> = 0> + template zoned_time(string_view _Name, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt) + requires requires { + { _Traits::locate_zone(_Name) } -> convertible_to<_TimeZonePtr>; + } && is_convertible_v, sys_time<_Duration>> : zoned_time{_Traits::locate_zone(_Name), _Zt} {} - template &, choose>, - int> = 0> + template zoned_time(string_view _Name, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt, choose _Choose) + requires requires { + { _Traits::locate_zone(_Name) } -> convertible_to<_TimeZonePtr>; + } && is_convertible_v, sys_time<_Duration>> : zoned_time{_Traits::locate_zone(_Name), _Zt, _Choose} {} zoned_time& operator=(const sys_time<_Duration>& _Sys) noexcept /* strengthened */ { From 58d2abc2faea3a9ef33225f7b0ae90f659fb211d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 24 Nov 2025 08:20:23 -0800 Subject: [PATCH 3/3] zoned_time: Avoid delegating constructors. In theory this repeats a bit of code, but IMO it clarifies what's happening (because zoned_time has so many constructors). This also avoids repeatedly evaluating constraints. --- stl/inc/chrono | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index aa3376966c0..dcb809a8341 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -2490,7 +2490,7 @@ namespace chrono { requires requires { { _Traits::locate_zone(_Name) } -> convertible_to<_TimeZonePtr>; } - : zoned_time{_Traits::locate_zone(_Name), _Sys} {} + : _Zone{_Traits::locate_zone(_Name)}, _Tp{_Sys} {} zoned_time(_TimeZonePtr _Tz, const local_time<_Duration>& _Local) requires requires { @@ -2503,7 +2503,7 @@ namespace chrono { { _Traits::locate_zone(_Name) } -> convertible_to<_TimeZonePtr>; { _STD declval<_TimeZonePtr&>() -> to_sys(_Local) } -> convertible_to>; } - : zoned_time{_Traits::locate_zone(_Name), _Local} {} + : _Zone{_Traits::locate_zone(_Name)}, _Tp{_Zone->to_sys(_Local)} {} zoned_time(_TimeZonePtr _Tz, const local_time<_Duration>& _Local, choose _Choose) requires requires { @@ -2516,7 +2516,7 @@ namespace chrono { { _Traits::locate_zone(_Name) } -> convertible_to<_TimeZonePtr>; { _STD declval<_TimeZonePtr&>() -> to_sys(_Local, _Choose) } -> convertible_to>; } - : zoned_time{_Traits::locate_zone(_Name), _Local, _Choose} {} + : _Zone{_Traits::locate_zone(_Name)}, _Tp{_Zone->to_sys(_Local, _Choose)} {} template requires is_convertible_v, sys_time<_Duration>> @@ -2527,21 +2527,21 @@ namespace chrono { requires is_convertible_v, sys_time<_Duration>> zoned_time( _TimeZonePtr _Tz, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt, choose) noexcept /* strengthened */ - : zoned_time{_Tz, _Zt} {} + : _Zone{_STD move(_Tz)}, _Tp{_Zt.get_sys_time()} {} template zoned_time(string_view _Name, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt) requires requires { { _Traits::locate_zone(_Name) } -> convertible_to<_TimeZonePtr>; } && is_convertible_v, sys_time<_Duration>> - : zoned_time{_Traits::locate_zone(_Name), _Zt} {} + : _Zone{_Traits::locate_zone(_Name)}, _Tp{_Zt.get_sys_time()} {} template - zoned_time(string_view _Name, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt, choose _Choose) + zoned_time(string_view _Name, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt, choose) requires requires { { _Traits::locate_zone(_Name) } -> convertible_to<_TimeZonePtr>; } && is_convertible_v, sys_time<_Duration>> - : zoned_time{_Traits::locate_zone(_Name), _Zt, _Choose} {} + : _Zone{_Traits::locate_zone(_Name)}, _Tp{_Zt.get_sys_time()} {} zoned_time& operator=(const sys_time<_Duration>& _Sys) noexcept /* strengthened */ { _Tp = _Sys;