Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions include/fmt/ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,6 @@ struct formatter<tuple_join_view<Tuple, Char>, Char,
return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
}
};

namespace detail {
// Check if T has an interface like a container adaptor (e.g. std::stack,
// std::queue, std::priority_queue).
Expand All @@ -766,10 +765,19 @@ template <typename Container> struct all {
};
} // namespace detail

/**
* returns "true" if "T" is a container adaptor (like "std::stack")
* that should be formatted by iterating over the underlying container.
* */

FMT_EXPORT
template <typename T>
struct is_container_adaptor : detail::is_container_adaptor_like<T> {};

template <typename T, typename Char>
struct formatter<
T, Char,
enable_if_t<conjunction<detail::is_container_adaptor_like<T>,
enable_if_t<conjunction<is_container_adaptor<T>,
bool_constant<range_format_kind<T, Char>::value ==
range_format::disabled>>::value>>
: formatter<detail::all<typename T::container_type>, Char> {
Expand Down
30 changes: 30 additions & 0 deletions test/ranges-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -797,3 +797,33 @@ struct not_range {
void end() const {}
};
static_assert(!fmt::is_formattable<not_range>{}, "");

namespace test_detail {
template <typename T>
struct partial_opt_out_wrapper {
using container_type = std::vector<T>;
std::vector<T> c = {1, 2, 3};
};
} // namespace test_detail

namespace fmt {
template <typename T>
struct is_container_adaptor<test_detail::partial_opt_out_wrapper<T>> : std::false_type {};

template <typename T>
struct formatter<test_detail::partial_opt_out_wrapper<T>> {
constexpr fmt::format_parse_context::iterator parse(fmt::format_parse_context& ctx) const {
return ctx.begin();
}

fmt::format_context::iterator format(const test_detail::partial_opt_out_wrapper<T>& val,
fmt::format_context& ctx) const {
return fmt::format_to(ctx.out(), "PartialOptOut(size={})", val.c.size());
}
};
} // namespace fmt

TEST(ranges_test, container_adaptor_partial_specialization) {
test_detail::partial_opt_out_wrapper<int> obj;
EXPECT_EQ(fmt::format("{}", obj), "PartialOptOut(size=3)");
}