From e1832bcf00ed53048aea1e4d2408a68301dcd50c Mon Sep 17 00:00:00 2001 From: Beat Bolli Date: Mon, 22 Jan 2024 16:39:33 +0100 Subject: [PATCH] Consider ADL begin() and end() when joining ranges (#3824) Closes #3813 Signed-off-by: Beat Bolli --- include/fmt/ranges.h | 21 +++++++++++++++++++-- test/ranges-test.cc | 16 ++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index 9499fa14c4b1..111993cd40ab 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -578,6 +578,22 @@ auto join(It begin, Sentinel end, string_view sep) -> join_view { return {begin, end, sep}; } +namespace detail { +// ADL helpers for fmt::join() +namespace adl { +using std::begin; +using std::end; + +template auto adlbegin(Range& r) -> decltype(begin(r)) { + return begin(r); +} + +template auto adlend(Range& r) -> decltype(end(r)) { + return end(r); +} +} // namespace adl +} // namespace detail + /** \rst Returns a view that formats `range` with elements separated by `sep`. @@ -596,8 +612,9 @@ auto join(It begin, Sentinel end, string_view sep) -> join_view { */ template auto join(Range&& range, string_view sep) - -> join_view { - return join(std::begin(range), std::end(range), sep); + -> join_view { + return join(detail::adl::adlbegin(range), detail::adl::adlend(range), sep); } template struct tuple_join_view : detail::view { diff --git a/test/ranges-test.cc b/test/ranges-test.cc index 3e9cbdc0d1f8..74cbc6194c0f 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -455,6 +455,22 @@ TEST(ranges_test, join_range) { "0,1,2,3,4"); # endif } + +namespace adl { +struct vec : std::vector { + using std::vector::vector; // inherit all constructors +}; + +// ADL-found begin() and end() skip the first and last element +auto begin(vec& v) -> typename vec::iterator { return v.begin() + 1; } +auto end(vec& v) -> typename vec::iterator { return v.end() - 1; } +} + +TEST(ranges_test, format_join_adl_begin_end) { + auto v = adl::vec{41, 42, 43, 44}; + EXPECT_EQ(fmt::format("{}", fmt::join(v, "/")), "42/43"); +} + #endif // FMT_RANGES_TEST_ENABLE_JOIN #if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 202302L