diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index 36b38e29..b9ec7ca4 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -347,6 +347,16 @@ template struct is_range { detail::is_range_::value && !detail::has_to_string_view::value; }; +/** + * returns "true" if "T" is a container adaptor (like "std::stack") + * that should be formatted by iterating over the underlying container. + * */ + +FMT_EXPORT +template +struct is_container_adaptor : std::true_type {}; + + namespace detail { template @@ -770,6 +780,7 @@ template struct formatter< T, Char, enable_if_t, + is_container_adaptor, // -> added the sanity checker bool_constant::value == range_format::disabled>>::value>> : formatter, Char> { diff --git a/test/ranges-test.cc b/test/ranges-test.cc index d65037fa..6d5cdaa8 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -5,6 +5,10 @@ // // For the license information refer to format.h. +#include "fmt/ranges.h" +#include "fmt/ranges.h" +#include "fmt/ranges.h" +#include "fmt/ranges.h" #include "fmt/ranges.h" #include @@ -17,6 +21,9 @@ #include #include +#include "posix-mock.h" +#include "fmt/base.h" + #if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE() # include #endif @@ -797,3 +804,43 @@ struct not_range { void end() const {} }; static_assert(!fmt::is_formattable{}, ""); + +namespace test_detail +{ + template + struct partial_opt_out_wrapper + { + using container_type = std::vector; + std::vector c = {1, 2, 3}; + auto begin() const {return c.begin(); } + auto end() const {return c.end(); } + + }; + +} +namespace fmt +{ + // disables is_range + template + struct fmt::is_range, char> : std::false_type{}; + // opt-out of the container adaptor format + template + struct fmt::is_container_adaptor> : std::false_type{}; +} +//a custom partial specializtion +template +struct fmt::formatter> +{ + constexpr auto parse(fmt::format_parse_context& ctx) { return ctx.begin(); } + auto format(const test_detail::partial_opt_out_wrapper& val, fmt::format_context& ctx) const + { + return fmt::format_to(ctx.out(), "PartialOptOut(size={})", val.c.size()); + } + +}; +TEST(ranges_test, container_adaptor_partial_specialization) +{ + test_detail::partial_opt_out_wrapper obj; + EXPECT_EQ(fmt::format("{}", obj), "PartialOptOut(size=3)"); +} +