Skip to content

Commit 5cc5072

Browse files
authored
Fix range suppresor formatter (#4660)
1 parent cf74caa commit 5cc5072

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

include/fmt/ranges.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,6 @@ struct formatter<tuple_join_view<Tuple, Char>, Char,
746746
return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
747747
}
748748
};
749-
750749
namespace detail {
751750
// Check if T has an interface like a container adaptor (e.g. std::stack,
752751
// std::queue, std::priority_queue).
@@ -766,10 +765,19 @@ template <typename Container> struct all {
766765
};
767766
} // namespace detail
768767

768+
/**
769+
* returns "true" if "T" is a container adaptor (like "std::stack")
770+
* that should be formatted by iterating over the underlying container.
771+
* */
772+
773+
FMT_EXPORT
774+
template <typename T>
775+
struct is_container_adaptor : detail::is_container_adaptor_like<T> {};
776+
769777
template <typename T, typename Char>
770778
struct formatter<
771779
T, Char,
772-
enable_if_t<conjunction<detail::is_container_adaptor_like<T>,
780+
enable_if_t<conjunction<is_container_adaptor<T>,
773781
bool_constant<range_format_kind<T, Char>::value ==
774782
range_format::disabled>>::value>>
775783
: formatter<detail::all<typename T::container_type>, Char> {

test/ranges-test.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,3 +797,33 @@ struct not_range {
797797
void end() const {}
798798
};
799799
static_assert(!fmt::is_formattable<not_range>{}, "");
800+
801+
namespace test_detail {
802+
template <typename T>
803+
struct partial_opt_out_wrapper {
804+
using container_type = std::vector<T>;
805+
std::vector<T> c = {1, 2, 3};
806+
};
807+
} // namespace test_detail
808+
809+
namespace fmt {
810+
template <typename T>
811+
struct is_container_adaptor<test_detail::partial_opt_out_wrapper<T>> : std::false_type {};
812+
813+
template <typename T>
814+
struct formatter<test_detail::partial_opt_out_wrapper<T>> {
815+
constexpr fmt::format_parse_context::iterator parse(fmt::format_parse_context& ctx) const {
816+
return ctx.begin();
817+
}
818+
819+
fmt::format_context::iterator format(const test_detail::partial_opt_out_wrapper<T>& val,
820+
fmt::format_context& ctx) const {
821+
return fmt::format_to(ctx.out(), "PartialOptOut(size={})", val.c.size());
822+
}
823+
};
824+
} // namespace fmt
825+
826+
TEST(ranges_test, container_adaptor_partial_specialization) {
827+
test_detail::partial_opt_out_wrapper<int> obj;
828+
EXPECT_EQ(fmt::format("{}", obj), "PartialOptOut(size=3)");
829+
}

0 commit comments

Comments
 (0)