Handle implicit conversions in write

This commit is contained in:
Victor Zverovich 2021-10-31 08:09:32 -07:00
parent 5b0aa638cf
commit 028f227752
2 changed files with 36 additions and 19 deletions

View File

@ -42,7 +42,7 @@
#include <utility> // std::swap
#ifdef __cpp_lib_bit_cast
#include <bit> // std::bitcast
# include <bit> // std::bitcast
#endif
#include "core.h"
@ -1720,7 +1720,7 @@ inline auto write_significand(Char* out, UInt significand, int significand_size,
out += significand_size + 1;
Char* end = out;
int floating_size = significand_size - integral_size;
for(int i = floating_size / 2; i > 0; --i) {
for (int i = floating_size / 2; i > 0; --i) {
out -= 2;
copy2(out, digits2(significand % 100));
significand /= 100;
@ -2082,7 +2082,7 @@ FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt {
return base_iterator(out, it);
}
// FMT_ENABLE_IF() condition separated to workaround MSVC bug
// FMT_ENABLE_IF() condition separated to workaround an MSVC bug.
template <
typename Char, typename OutputIt, typename T,
bool check =
@ -2133,18 +2133,28 @@ auto write(OutputIt out, const T* value,
return write_ptr<Char>(out, to_uintptr(value), &specs);
}
template <typename Char, typename OutputIt, typename T>
FMT_CONSTEXPR auto write(OutputIt out, const T& value) ->
typename std::enable_if<
mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value ==
type::custom_type,
OutputIt>::type {
using context_type = basic_format_context<OutputIt, Char>;
// A write overload that handles implicit conversions.
template <typename Char, typename OutputIt, typename T,
typename Context = basic_format_context<OutputIt, Char>>
FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t<
std::is_class<T>::value && !is_string<T>::value &&
!std::is_same<T, Char>::value &&
!std::is_same<const T&,
decltype(arg_mapper<Context>().map(value))>::value,
OutputIt> {
return write<Char>(out, arg_mapper<Context>().map(value));
}
template <typename Char, typename OutputIt, typename T,
typename Context = basic_format_context<OutputIt, Char>>
FMT_CONSTEXPR auto write(OutputIt out, const T& value)
-> enable_if_t<mapped_type_constant<T, Context>::value == type::custom_type,
OutputIt> {
using formatter_type =
conditional_t<has_formatter<T, context_type>::value,
typename context_type::template formatter_type<T>,
conditional_t<has_formatter<T, Context>::value,
typename Context::template formatter_type<T>,
fallback_formatter<T, Char>>;
context_type ctx(out, {}, {});
auto ctx = Context(out, {}, {});
return formatter_type().format(value, ctx);
}

View File

@ -1820,13 +1820,20 @@ struct formatter<adl_test::fmt::detail::foo> : formatter<std::string> {
};
FMT_END_NAMESPACE
TEST(format_test, to_string) {
EXPECT_EQ("42", fmt::to_string(42));
EXPECT_EQ("0x1234", fmt::to_string(reinterpret_cast<void*>(0x1234)));
EXPECT_EQ("foo", fmt::to_string(adl_test::fmt::detail::foo()));
struct convertible_to_int {
operator int() const { return value; }
enum test_enum2 : unsigned char { test_value };
EXPECT_EQ("0", fmt::to_string(test_value));
int value = 42;
};
TEST(format_test, to_string) {
EXPECT_EQ(fmt::to_string(42), "42");
EXPECT_EQ(fmt::to_string(reinterpret_cast<void*>(0x1234)), "0x1234");
EXPECT_EQ(fmt::to_string(adl_test::fmt::detail::foo()), "foo");
EXPECT_EQ(fmt::to_string(convertible_to_int()), "42");
enum foo : unsigned char { zero };
EXPECT_EQ(fmt::to_string(zero), "0");
}
TEST(format_test, output_iterators) {