@@ -212,7 +212,8 @@ namespace chrono {
212212 using rep = typename _Duration::rep;
213213 using period = typename _Duration::period;
214214
215- static_assert(_Is_duration_v<_Duration>, "duration must be an instance of std::duration");
215+ static_assert(_Is_duration_v<_Duration>,
216+ "N4885 [time.point.general]/1 mandates Duration to be a specialization of chrono::duration.");
216217
217218 constexpr time_point() = default;
218219
@@ -2128,8 +2129,11 @@ namespace chrono {
21282129 }
21292130
21302131 template <class _Duration>
2131- requires _Is_duration_v<_Duration> class hh_mm_ss {
2132+ class hh_mm_ss {
21322133 public:
2134+ static_assert(_Is_duration_v<_Duration>,
2135+ "N4885 [time.hms.overview]/2 mandates Duration to be a specialization of chrono::duration.");
2136+
21332137 static constexpr unsigned int fractional_width = [] {
21342138 auto _Num = _Duration::period::num;
21352139 constexpr auto _Den = _Duration::period::den;
@@ -2907,19 +2911,19 @@ namespace chrono {
29072911 class zoned_time {
29082912 private:
29092913 static_assert(_Is_duration_v<_Duration>,
2910- "N4878 [time.zone.zonedtime.overview]/2 requires Duration to be a specialization of chrono::duration.");
2914+ "N4885 [time.zone.zonedtime.overview]/2 mandates Duration to be a specialization of chrono::duration.");
29112915
29122916 using _Traits = zoned_traits<_TimeZonePtr>;
29132917
29142918 public:
29152919 using duration = common_type_t<_Duration, seconds>;
29162920
2917- template <class _Traits2 = _Traits, class = decltype(_Traits2::default_zone())>
2921+ template <class _Traits2 = _Traits, class = void_t< decltype(_Traits2::default_zone())> >
29182922 zoned_time() : _Zone{_Traits::default_zone()} {}
29192923 zoned_time(const zoned_time&) = default;
29202924 zoned_time& operator=(const zoned_time&) = default;
29212925
2922- template <class _Traits2 = _Traits, class = decltype(_Traits2::default_zone())>
2926+ template <class _Traits2 = _Traits, class = void_t< decltype(_Traits2::default_zone())> >
29232927 zoned_time(const sys_time<_Duration>& _Sys) : _Zone{_Traits::default_zone()}, _Tp{_Sys} {}
29242928
29252929 explicit zoned_time(_TimeZonePtr _Tz) noexcept /* strengthened */ : _Zone{_STD move(_Tz)} {}
@@ -3405,131 +3409,174 @@ namespace chrono {
34053409
34063410 // [time.clock.cast.sys]
34073411
3408- // TRANSITION, GH-395 workaround, is_same_v -> same_as
3409- template <class _Ty, class _Clock>
3410- concept _Is_time_point = requires {
3411- typename _Ty::duration;
3412- requires is_same_v<time_point<_Clock, typename _Ty::duration>, _Ty>;
3413- };
3412+ template <class _TimePoint, class _Clock>
3413+ inline constexpr bool _Is_time_point_for_clock = false;
34143414
34153415 template <class _Clock, class _Duration>
3416- concept _Convertible_to_sys_time =
3417- is_same_v<_Clock, system_clock> || requires(const time_point<_Clock, _Duration>& _Time) {
3418- { _Clock::to_sys(_Time) }
3419- ->_Is_time_point<system_clock>;
3420- };
3421-
3422- template <class _Clock, class _Duration>
3423- concept _Convertible_from_sys_time = is_same_v<_Clock, system_clock> || requires(const sys_time<_Duration>& _Time) {
3424- { _Clock::from_sys(_Time) }
3425- ->_Is_time_point<_Clock>;
3426- };
3416+ inline constexpr bool _Is_time_point_for_clock<time_point<_Clock, _Duration>, _Clock> = true;
34273417
34283418 template <class _SourceClock>
34293419 struct clock_time_conversion<system_clock, _SourceClock> {
3430- template <class _Duration>
3420+ template <class _Duration, class _SourceClock2 = _SourceClock,
3421+ class =
3422+ void_t<decltype(_SourceClock2::to_sys(_STD declval<const time_point<_SourceClock2, _Duration>&>()))>>
34313423 _NODISCARD auto operator()(const time_point<_SourceClock, _Duration>& _Time) const
3432- noexcept(noexcept(_SourceClock::to_sys(_Time))) /* strengthened */
3433- requires _Convertible_to_sys_time<_SourceClock, _Duration> {
3424+ noexcept(noexcept(_SourceClock::to_sys(_Time))) /* strengthened */ {
3425+ static_assert(_Is_time_point_for_clock<decltype(_SourceClock::to_sys(_Time)), system_clock>,
3426+ "N4885 [time.clock.cast.sys]/2: Mandates: SourceClock::to_sys(t) returns a sys_time<Duration>");
34343427 return _SourceClock::to_sys(_Time);
34353428 }
34363429 };
34373430
34383431 template <class _DestClock>
34393432 struct clock_time_conversion<_DestClock, system_clock> {
3440- template <class _Duration>
3433+ template <class _Duration, class _DestClock2 = _DestClock,
3434+ class = void_t<decltype(_DestClock2::from_sys(_STD declval<const sys_time<_Duration>&>()))>>
34413435 _NODISCARD auto operator()(const sys_time<_Duration>& _Time) const
3442- noexcept(noexcept(_DestClock::from_sys(_Time))) /* strengthened */
3443- requires _Convertible_from_sys_time<_DestClock, _Duration> {
3436+ noexcept(noexcept(_DestClock::from_sys(_Time))) /* strengthened */ {
3437+ static_assert(_Is_time_point_for_clock<decltype(_DestClock::from_sys(_Time)), _DestClock>,
3438+ "N4885 [time.clock.cast.sys]/5: Mandates: DestClock::from_sys(t) returns a "
3439+ "time_point<DestClock, Duration>");
34443440 return _DestClock::from_sys(_Time);
34453441 }
34463442 };
34473443
34483444 // [time.clock.cast.utc]
34493445
3450- template <class _Clock, class _Duration>
3451- concept _Convertible_to_utc_time =
3452- is_same_v<_Clock,
3453- utc_clock> || is_same_v<_Clock, system_clock> || requires(const time_point<_Clock, _Duration>& _Time) {
3454- { _Clock::to_utc(_Time) }
3455- ->_Is_time_point<utc_clock>;
3456- };
3457-
3458- template <class _Clock, class _Duration>
3459- concept _Convertible_from_utc_time =
3460- is_same_v<_Clock, utc_clock> || is_same_v<_Clock, system_clock> || requires(const utc_time<_Duration>& _Time) {
3461- { _Clock::from_utc(_Time) }
3462- ->_Is_time_point<_Clock>;
3463- };
3464-
34653446 template <class _SourceClock>
34663447 struct clock_time_conversion<utc_clock, _SourceClock> {
3467- template <class _Duration>
3448+ template <class _Duration, class _SourceClock2 = _SourceClock,
3449+ class =
3450+ void_t<decltype(_SourceClock2::to_utc(_STD declval<const time_point<_SourceClock2, _Duration>&>()))>>
34683451 _NODISCARD auto operator()(const time_point<_SourceClock, _Duration>& _Time) const
3469- noexcept(noexcept(_SourceClock::to_utc(_Time))) /* strengthened */
3470- requires _Convertible_to_utc_time<_SourceClock, _Duration> {
3452+ noexcept(noexcept(_SourceClock::to_utc(_Time))) /* strengthened */ {
3453+ static_assert(_Is_time_point_for_clock<decltype(_SourceClock::to_utc(_Time)), utc_clock>,
3454+ "N4885 [time.clock.cast.utc]/2: Mandates: SourceClock::to_utc(t) returns a utc_time<Duration>");
34713455 return _SourceClock::to_utc(_Time);
34723456 }
34733457 };
34743458
34753459 template <class _DestClock>
34763460 struct clock_time_conversion<_DestClock, utc_clock> {
3477- template <class _Duration>
3461+ template <class _Duration, class _DestClock2 = _DestClock,
3462+ class = void_t<decltype(_DestClock2::from_utc(_STD declval<const utc_time<_Duration>&>()))>>
34783463 _NODISCARD auto operator()(const utc_time<_Duration>& _Time) const
3479- noexcept(noexcept(_DestClock::from_utc(_Time))) /* strengthened */
3480- requires _Convertible_from_utc_time<_DestClock, _Duration> {
3464+ noexcept(noexcept(_DestClock::from_utc(_Time))) /* strengthened */ {
3465+ static_assert(_Is_time_point_for_clock<decltype(_DestClock::from_utc(_Time)), _DestClock>,
3466+ "N4885 [time.clock.cast.utc]/5: Mandates: DestClock::from_utc(t) returns a "
3467+ "time_point<DestClock, Duration>");
34813468 return _DestClock::from_utc(_Time);
34823469 }
34833470 };
34843471
34853472 // [time.clock.cast.fn]
34863473
3487- // FUNCTION TEMPLATE clock_cast
3474+ enum class _Clock_cast_strategy {
3475+ _Direct,
3476+ _Via_sys,
3477+ _Via_utc,
3478+ _Via_utc_from_sys,
3479+ _Via_sys_from_utc,
3480+ _Two_step_ambiguous,
3481+ _Three_step_ambiguous,
3482+ _None,
3483+ };
3484+
3485+ template <class _Conv1, class _Conv2, class _Tp, class = void>
3486+ inline constexpr bool _Has_two_step_conversion = false;
3487+
3488+ template <class _Conv1, class _Conv2, class _Tp>
3489+ inline constexpr bool
3490+ _Has_two_step_conversion<_Conv1, _Conv2, _Tp, void_t<decltype(_Conv1{}(_Conv2{}(_STD declval<_Tp>())))>> = true;
3491+
3492+ template <class _Conv1, class _Conv2, class _Conv3, class _Tp, class = void>
3493+ inline constexpr bool _Has_three_step_conversion = false;
3494+
3495+ template <class _Conv1, class _Conv2, class _Conv3, class _Tp>
3496+ inline constexpr bool _Has_three_step_conversion<_Conv1, _Conv2, _Conv3, _Tp,
3497+ void_t<decltype(_Conv1{}(_Conv2{}(_Conv3{}(_STD declval<_Tp>()))))>> = true;
3498+
3499+ template <class _DestClock, class _SourceClock, class _Duration>
3500+ _NODISCARD _CONSTEVAL _Clock_cast_strategy _Choose_clock_cast() noexcept {
3501+ using _Tp = const time_point<_SourceClock, _Duration>&;
3502+
3503+ if constexpr (is_invocable_v<clock_time_conversion<_DestClock, _SourceClock>, _Tp>) {
3504+ return _Clock_cast_strategy::_Direct;
3505+ } else {
3506+ constexpr bool _Has_sys = _Has_two_step_conversion< //
3507+ clock_time_conversion<_DestClock, system_clock>, //
3508+ clock_time_conversion<system_clock, _SourceClock>, _Tp>;
3509+
3510+ constexpr bool _Has_utc = _Has_two_step_conversion< //
3511+ clock_time_conversion<_DestClock, utc_clock>, //
3512+ clock_time_conversion<utc_clock, _SourceClock>, _Tp>;
3513+
3514+ if constexpr (_Has_sys && _Has_utc) {
3515+ return _Clock_cast_strategy::_Two_step_ambiguous;
3516+ } else if constexpr (_Has_sys) {
3517+ return _Clock_cast_strategy::_Via_sys;
3518+ } else if constexpr (_Has_utc) {
3519+ return _Clock_cast_strategy::_Via_utc;
3520+ } else {
3521+ constexpr bool _Has_utc_from_sys = _Has_three_step_conversion< //
3522+ clock_time_conversion<_DestClock, utc_clock>, //
3523+ clock_time_conversion<utc_clock, system_clock>, //
3524+ clock_time_conversion<system_clock, _SourceClock>, _Tp>;
3525+
3526+ constexpr bool _Has_sys_from_utc = _Has_three_step_conversion< //
3527+ clock_time_conversion<_DestClock, system_clock>, //
3528+ clock_time_conversion<system_clock, utc_clock>, //
3529+ clock_time_conversion<utc_clock, _SourceClock>, _Tp>;
3530+
3531+ if constexpr (_Has_utc_from_sys && _Has_sys_from_utc) {
3532+ return _Clock_cast_strategy::_Three_step_ambiguous;
3533+ } else if constexpr (_Has_utc_from_sys) {
3534+ return _Clock_cast_strategy::_Via_utc_from_sys;
3535+ } else if constexpr (_Has_sys_from_utc) {
3536+ return _Clock_cast_strategy::_Via_sys_from_utc;
3537+ } else {
3538+ return _Clock_cast_strategy::_None;
3539+ }
3540+ }
3541+ }
3542+ }
3543+
34883544 template <class _DestClock, class _SourceClock, class _Duration>
3545+ inline constexpr auto _Clock_cast_choice = _Choose_clock_cast<_DestClock, _SourceClock, _Duration>();
3546+
3547+ // FUNCTION TEMPLATE clock_cast
3548+ template <class _DestClock, class _SourceClock, class _Duration,
3549+ enable_if_t<_Clock_cast_choice<_DestClock, _SourceClock, _Duration> != _Clock_cast_strategy::_None, int> = 0>
34893550 _NODISCARD auto clock_cast(const time_point<_SourceClock, _Duration>& _Time) {
3490- constexpr bool _Has_direct_conversion =
3491- is_invocable_v<clock_time_conversion<_DestClock, _SourceClock>, decltype(_Time)>;
3492-
3493- constexpr bool _Utc_from_src = _Convertible_to_utc_time<_SourceClock, _Duration>;
3494- constexpr bool _Sys_from_src = _Convertible_to_sys_time<_SourceClock, _Duration>;
3495- constexpr bool _Dest_from_utc = _Convertible_from_utc_time<_DestClock, _Duration>;
3496- constexpr bool _Dest_from_sys = _Convertible_from_sys_time<_DestClock, _Duration>;
3497-
3498- constexpr bool _Has_utc_conversion = _Dest_from_utc && _Utc_from_src;
3499- constexpr bool _Has_sys_conversion = _Dest_from_sys && _Sys_from_src;
3500- static_assert(_Has_direct_conversion || !(_Has_utc_conversion && _Has_sys_conversion),
3501- "A two-step clock time conversion is required to be unique, either through utc_clock or system_clock, but "
3502- "not both (N4878 [time.clock.cast.fn]/2.)");
3503-
3504- constexpr bool _Has_sys_utc_conversion = _Dest_from_sys && _Utc_from_src;
3505- constexpr bool _Has_utc_sys_conversion = _Dest_from_utc && _Sys_from_src;
3506- static_assert(_Has_direct_conversion || _Has_utc_conversion || _Has_sys_conversion
3507- || !(_Has_utc_sys_conversion && _Has_sys_utc_conversion),
3508- "A three-step clock time conversion is required to be unique, either utc-to-system or system-to-utc, but "
3509- "not both (N4878 [time.clock.cast.fn]/2).");
3551+ constexpr auto _Strat = _Clock_cast_choice<_DestClock, _SourceClock, _Duration>;
35103552
3511- // clang-format off
3512- if constexpr (_Has_direct_conversion) {
3553+ if constexpr (_Strat == _Clock_cast_strategy::_Direct) {
35133554 return clock_time_conversion<_DestClock, _SourceClock>{}(_Time);
3514- } else if constexpr (_Has_utc_conversion) {
3515- return clock_time_conversion<_DestClock, utc_clock>{}(
3516- clock_time_conversion<utc_clock, _SourceClock>{}(_Time));
3517- } else if constexpr (_Has_sys_conversion) {
3555+ } else if constexpr (_Strat == _Clock_cast_strategy::_Via_sys) {
35183556 return clock_time_conversion<_DestClock, system_clock>{}(
3519- clock_time_conversion<system_clock, _SourceClock>{}(_Time));
3520- } else if constexpr (_Has_sys_utc_conversion) {
3521- return clock_time_conversion<_DestClock, system_clock>{}(
3522- clock_time_conversion<system_clock, utc_clock>{}(
3523- clock_time_conversion<utc_clock, _SourceClock>{}(_Time)));
3524- } else if constexpr (_Has_utc_sys_conversion) {
3557+ clock_time_conversion<system_clock, _SourceClock>{}(_Time));
3558+ } else if constexpr (_Strat == _Clock_cast_strategy::_Via_utc) {
35253559 return clock_time_conversion<_DestClock, utc_clock>{}(
3526- clock_time_conversion<utc_clock, system_clock>{}(
3527- clock_time_conversion<system_clock, _SourceClock>{}(_Time)));
3560+ clock_time_conversion<utc_clock, _SourceClock>{}(_Time));
3561+ } else if constexpr (_Strat == _Clock_cast_strategy::_Via_utc_from_sys) {
3562+ return clock_time_conversion<_DestClock, utc_clock>{}( //
3563+ clock_time_conversion<utc_clock, system_clock>{}(
3564+ clock_time_conversion<system_clock, _SourceClock>{}(_Time)));
3565+ } else if constexpr (_Strat == _Clock_cast_strategy::_Via_sys_from_utc) {
3566+ return clock_time_conversion<_DestClock, system_clock>{}( //
3567+ clock_time_conversion<system_clock, utc_clock>{}(
3568+ clock_time_conversion<utc_clock, _SourceClock>{}(_Time)));
3569+ } else if constexpr (_Strat == _Clock_cast_strategy::_Two_step_ambiguous) {
3570+ static_assert(_Always_false<_Duration>,
3571+ "A two-step clock time conversion is required to be unique, "
3572+ "either through utc_clock or system_clock, but not both (N4878 [time.clock.cast.fn]/2).");
3573+ } else if constexpr (_Strat == _Clock_cast_strategy::_Three_step_ambiguous) {
3574+ static_assert(_Always_false<_Duration>,
3575+ "A three-step clock time conversion is required to be unique, "
3576+ "either utc-to-system or system-to-utc, but not both (N4878 [time.clock.cast.fn]/2).");
35283577 } else {
3529- static_assert(_Always_false<_Duration>, "No clock time conversion exists from source clock type to "
3530- "destination clock type (N4878 [time.clock.cast.fn]/1).");
3578+ static_assert(_Always_false<_Duration>, "should be unreachable");
35313579 }
3532- // clang-format on
35333580 }
35343581
35353582 // [time.parse]
0 commit comments