Skip to content

Commit 3030afb

Browse files
Implement LWG-3956 chrono::parse uses from_stream as a customization point (#5334)
Co-authored-by: Stephan T. Lavavej <stl@microsoft.com>
1 parent cc11d08 commit 3030afb

File tree

2 files changed

+63
-6
lines changed
  • stl/inc
  • tests/std/tests/P0355R7_calendars_and_time_zones_io

2 files changed

+63
-6
lines changed

stl/inc/chrono

+18-6
Original file line numberDiff line numberDiff line change
@@ -4608,6 +4608,22 @@ namespace chrono {
46084608
return _Istr;
46094609
}
46104610

4611+
namespace _From_stream_adl_only {
4612+
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199
4613+
void from_stream() = delete; // Block unqualified name lookup
4614+
#else // ^^^ no workaround / workaround vvv
4615+
void from_stream();
4616+
#endif // ^^^ workaround ^^^
4617+
4618+
template <class _Parsable, class _CharT, class _Traits, class... _Rest>
4619+
concept _Can_from_stream = requires(
4620+
basic_istream<_CharT, _Traits>& __istr, const _CharT* __s, _Parsable& __parsed, _Rest&&... __rest_args) {
4621+
from_stream(__istr, +__s, __parsed, _STD forward<_Rest>(__rest_args)...); // intentional ADL
4622+
};
4623+
} // namespace _From_stream_adl_only
4624+
4625+
using _From_stream_adl_only::_Can_from_stream;
4626+
46114627
template <class _CharT, class _Traits, class _Alloc, class _Parsable>
46124628
struct _Time_parse_iomanip_c_str {
46134629
_Time_parse_iomanip_c_str(const _CharT* _Fmt_, _Parsable& _Tp_,
@@ -4618,6 +4634,7 @@ namespace chrono {
46184634

46194635
friend basic_istream<_CharT, _Traits>& operator>>(
46204636
basic_istream<_CharT, _Traits>& _Is, _Time_parse_iomanip_c_str&& _Tpi) {
4637+
using _From_stream_adl_only::from_stream;
46214638
from_stream(_Is, _Tpi._Fmt, _Tpi._Tp, _Tpi._Abbrev, _Tpi._Offset); // intentional ADL
46224639
return _Is;
46234640
}
@@ -4638,6 +4655,7 @@ namespace chrono {
46384655

46394656
friend basic_istream<_CharT, _Traits>& operator>>(
46404657
basic_istream<_CharT, _Traits>& _Is, _Time_parse_iomanip&& _Tpi) {
4658+
using _From_stream_adl_only::from_stream;
46414659
from_stream(_Is, _Tpi._Fmt.c_str(), _Tpi._Tp, _Tpi._Abbrev, _Tpi._Offset); // intentional ADL
46424660
return _Is;
46434661
}
@@ -4648,12 +4666,6 @@ namespace chrono {
46484666
minutes* _Offset;
46494667
};
46504668

4651-
template <class _Parsable, class _CharT, class _Traits, class... _Rest>
4652-
concept _Can_from_stream = requires(
4653-
basic_istream<_CharT, _Traits>& __istr, const _CharT* __s, _Parsable& __parsed, _Rest&&... __rest_args) {
4654-
from_stream(__istr, +__s, __parsed, _STD forward<_Rest>(__rest_args)...); // intentional ADL
4655-
};
4656-
46574669
_EXPORT_STD template <class _CharT, _Can_from_stream<_CharT, char_traits<_CharT>> _Parsable>
46584670
_NODISCARD auto parse(const _CharT* _Fmt, _Parsable& _Tp) {
46594671
return _Time_parse_iomanip_c_str<_CharT, char_traits<_CharT>, allocator<_CharT>, _Parsable>{_Fmt, _Tp};

tests/std/tests/P0355R7_calendars_and_time_zones_io/test.cpp

+45
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <charconv>
77
#include <chrono>
88
#include <cstdint>
9+
#include <istream>
910
#include <iterator>
1011
#include <limits>
1112
#include <locale>
@@ -1247,8 +1248,52 @@ void test_io_manipulator() {
12471248
fail_parse(WIDEN(CharT, "a b"), CStringOrStdString{WIDEN(CharT, "a%nb")}, time);
12481249
}
12491250

1251+
namespace lwg_3956 {
1252+
struct has_adl_from_stream {
1253+
int value = 0;
1254+
1255+
template <class CharT, class Traits, class... ArgTypes>
1256+
friend basic_istream<CharT, Traits>& from_stream(
1257+
basic_istream<CharT, Traits>& istr, const CharT*, has_adl_from_stream& parsed, ArgTypes&&...) {
1258+
parsed.value = 42;
1259+
return istr;
1260+
}
1261+
};
1262+
1263+
struct has_no_adl_from_stream {
1264+
operator year&() &;
1265+
};
1266+
1267+
template <class... ArgTypes>
1268+
concept can_parse = requires(ArgTypes&&... args) { parse(forward<ArgTypes>(args)...); };
1269+
1270+
static_assert(can_parse<const char*, has_adl_from_stream&>);
1271+
static_assert(can_parse<const string&, has_adl_from_stream&>);
1272+
static_assert(can_parse<const wchar_t*, has_adl_from_stream&>);
1273+
static_assert(can_parse<const wstring&, has_adl_from_stream&>);
1274+
1275+
static_assert(!can_parse<const char*, has_no_adl_from_stream&>);
1276+
static_assert(!can_parse<const string&, has_no_adl_from_stream&>);
1277+
static_assert(!can_parse<const wchar_t*, has_no_adl_from_stream&>);
1278+
static_assert(!can_parse<const wstring&, has_no_adl_from_stream&>);
1279+
} // namespace lwg_3956
1280+
1281+
void test_lwg_3956() {
1282+
{
1283+
lwg_3956::has_adl_from_stream parsed{};
1284+
test_parse("", "", parsed);
1285+
assert(parsed.value == 42);
1286+
}
1287+
{
1288+
lwg_3956::has_adl_from_stream parsed{};
1289+
test_parse(L"", L"", parsed);
1290+
assert(parsed.value == 42);
1291+
}
1292+
}
1293+
12501294
void test_parse() {
12511295
test_lwg_3536();
1296+
test_lwg_3956();
12521297
parse_seconds();
12531298
parse_minutes();
12541299
parse_hours();

0 commit comments

Comments
 (0)