Skip to content

Commit

Permalink
Fix formatting of ranges with begin()&/end()&
Browse files Browse the repository at this point in the history
C++20 allows ranges to have lvalue-qualified begin() and end() member functions. fmt correctly handles this if begin() and end() are additionally const-qualifed (i.e. begin() const&), but not in the non-const case. For example:

https://godbolt.org/z/YfxaYz5r7

This patch fixes fmt's range detection to handle this case by testing calls to detail::ranges_begin()/end() with an lvalue T&, matching the behaviour in the const case.
  • Loading branch information
tcbrindle authored and vitaut committed Jan 10, 2024
1 parent 6f5d53c commit 2595bf5
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 2 deletions.
4 changes: 2 additions & 2 deletions include/fmt/ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ struct has_const_begin_end<

template <typename T>
struct has_mutable_begin_end<
T, void_t<decltype(detail::range_begin(std::declval<T>())),
decltype(detail::range_end(std::declval<T>())),
T, void_t<decltype(detail::range_begin(std::declval<T&>())),
decltype(detail::range_end(std::declval<T&>())),
// the extra int here is because older versions of MSVC don't
// SFINAE properly unless there are distinct types
int>> : std::true_type {};
Expand Down
11 changes: 11 additions & 0 deletions test/ranges-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -592,3 +592,14 @@ auto format_as(const tieable& t) -> std::tuple<int, double> {
TEST(ranges_test, format_as_tie) {
EXPECT_EQ(fmt::format("{}", tieable()), "(3, 0.42)");
}

struct lvalue_qualified_begin_end {
int arr[5] = {1, 2, 3, 4, 5};

int const* begin() & { return arr; }
int const* end() & { return arr + 5; }
};

TEST(ranges_test, lvalue_qualified_begin_end) {
EXPECT_EQ(fmt::format("{}", lvalue_qualified_begin_end{}), "[1, 2, 3, 4, 5]");
}

0 comments on commit 2595bf5

Please sign in to comment.