diff --git a/stl/inc/chrono b/stl/inc/chrono index 85ef562b80..46e0ac3292 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -5302,7 +5302,9 @@ namespace chrono { } _EXPORT_STD template - basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const local_time<_Duration>& _Val) { + basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const local_time<_Duration>& _Val) + requires requires { _Os << sys_time<_Duration>{_Val.time_since_epoch()}; } + { return _Os << sys_time<_Duration>{_Val.time_since_epoch()}; } diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp index abb71a2505..26c4fc14db 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp @@ -20,6 +20,8 @@ #include +// Extended to test LWG-4257 "Stream insertion for chrono::local_time should be constrained" + using namespace std; using namespace chrono; @@ -1067,9 +1069,44 @@ void test_unsigned_sys_time_format_after_LWG_4274() { assert(s == "1970-01-01 00:00:00"); } +template +concept ostream_insertable = requires(ostream& o, const T& t) { o << t; }; + +template +void check_stream_insertion_operator_for_duration() { + if constexpr (ostream_insertable>) { + ostringstream oss; + oss << sys_time{}; + assert(oss.str() == "1970-01-01 00:00:00"); + } + + if constexpr (ostream_insertable>) { + ostringstream oss; + oss << local_time{}; + assert(oss.str() == "1970-01-01 00:00:00"); + } +} + +// Test based on example in LWG-4257 +void check_stream_insertion_operator() { + // operator<< is constrained such that it does not participate when underlying duration has floating-point rep + using ok_dur = duration; + using bad_dur = duration; + + static_assert(ostream_insertable>); + static_assert(ostream_insertable>); + check_stream_insertion_operator_for_duration(); + + static_assert(!ostream_insertable>); + static_assert(!ostream_insertable>); + check_stream_insertion_operator_for_duration(); +} + void test() { test_unsigned_sys_time_format_after_LWG_4274(); + check_stream_insertion_operator(); + test_parse_conversion_spec(); test_parse_conversion_spec();