Skip to content

Commit

Permalink
Consider ADL begin() and end() when joining ranges
Browse files Browse the repository at this point in the history
Closes fmtlib#3813

Signed-off-by: Beat Bolli <[email protected]>
  • Loading branch information
bbolli committed Jan 21, 2024
1 parent 11ba127 commit 48e3ab5
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 2 deletions.
21 changes: 19 additions & 2 deletions include/fmt/ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,22 @@ auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
return {begin, end, sep};
}

namespace detail {
// ADL helpers for fmt::join()
namespace adl {
using std::begin;
using std::end;

template <typename Range> auto adlbegin(Range& r) -> decltype(begin(r)) {
return begin(r);
}

template <typename Range> 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`.
Expand All @@ -596,8 +612,9 @@ auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
*/
template <typename Range>
auto join(Range&& range, string_view sep)
-> join_view<decltype(std::begin(range)), decltype(std::end(range))> {
return join(std::begin(range), std::end(range), sep);
-> join_view<decltype(detail::adl::adlbegin(range)),
decltype(detail::adl::adlend(range))> {
return join(detail::adl::adlbegin(range), detail::adl::adlend(range), sep);
}

template <typename Char, typename... T> struct tuple_join_view : detail::view {
Expand Down
16 changes: 16 additions & 0 deletions test/ranges-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,22 @@ TEST(ranges_test, join_range) {
"0,1,2,3,4");
# endif
}

namespace adl {
struct vec : std::vector<int> {
using std::vector<int>::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
Expand Down

0 comments on commit 48e3ab5

Please sign in to comment.