diff --git a/include/fmt/core.h b/include/fmt/core.h index f6886cf4..1f3e5801 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -13,6 +13,7 @@ #include // std::strlen #include #include +#include // std::addressof #include #include @@ -1281,9 +1282,9 @@ template class value { FMT_INLINE value(const named_arg_info* args, size_t size) : named_args{args, size} {} - template FMT_CONSTEXPR FMT_INLINE value(T& val) { + template FMT_CONSTEXPR20 FMT_INLINE value(T& val) { using value_type = remove_const_t; - custom.value = const_cast(&val); + custom.value = const_cast(std::addressof(val)); // Get the formatter type through the context to allow different contexts // have different extension points, e.g. `formatter` for `format` and // `printf_formatter` for `printf`. diff --git a/include/fmt/std.h b/include/fmt/std.h index a71a59db..b0e78e10 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -8,6 +8,7 @@ #ifndef FMT_STD_H_ #define FMT_STD_H_ +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include "format.h" #include "ostream.h" @@ -389,6 +391,50 @@ struct formatter< #endif } }; + +namespace detail { + +template +struct has_flip : std::false_type {}; + +template +struct has_flip().flip())>> + : std::true_type {}; + +template struct is_bit_reference_like { + static constexpr const bool value = + std::is_convertible::value && + std::is_nothrow_assignable::value && has_flip::value; +}; + +#ifdef _LIBCPP_VERSION + +// Workaround for libc++ incompatibility with C++ standard. +// According to the Standard, `bitset::operator[] const` returns bool. +template +struct is_bit_reference_like> { + static constexpr const bool value = true; +}; + +#endif + +} // namespace detail + +// We can't use std::vector::reference and +// std::bitset::reference because the compiler can't deduce Allocator and N +// in partial specialization. +FMT_EXPORT +template +struct formatter::value>> + : formatter { + template + FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter::format(v, ctx); + } +}; + FMT_END_NAMESPACE #endif // FMT_STD_H_ diff --git a/test/std-test.cc b/test/std-test.cc index fda8e96b..17b4792c 100644 --- a/test/std-test.cc +++ b/test/std-test.cc @@ -7,6 +7,7 @@ #include "fmt/std.h" +#include #include #include #include @@ -221,3 +222,17 @@ TEST(std_test, exception) { } #endif } + +TEST(std_test, format_bit_reference) { + std::bitset<2> bs(1); + EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false"); + std::vector v = {true, false}; + EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); +} + +TEST(std_test, format_const_bit_reference) { + const std::bitset<2> bs(1); + EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false"); + const std::vector v = {true, false}; + EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); +}