From 1c7b751d70075972aec6f908d149539ebd36a3ba Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 1 Feb 2018 15:21:57 -0800 Subject: [PATCH] Fix handling of implicit conversion to integral types larger than int --- include/fmt/core.h | 61 ++++++++++++++++++++++++++------------------- test/format-test.cc | 8 ++++++ 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index 30a592dd..697f4a60 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -353,22 +353,6 @@ inline void require_wchar() { "formatting of wide characters into a narrow output is disallowed"); } -template -struct convert_to_int { - enum { - value = !std::is_arithmetic::value && std::is_convertible::value - }; -}; - -#define FMT_DISABLE_CONVERSION_TO_INT(Type) \ - template <> \ - struct convert_to_int { enum { value = 0 }; } - -// Silence warnings about convering float to int. -FMT_DISABLE_CONVERSION_TO_INT(float); -FMT_DISABLE_CONVERSION_TO_INT(double); -FMT_DISABLE_CONVERSION_TO_INT(long double); - template struct named_arg_base; @@ -400,12 +384,46 @@ constexpr bool is_arithmetic(type t) { return t > internal::NONE && t <= internal::LAST_NUMERIC_TYPE; } +template +struct convert_to_int { + enum { + value = !std::is_arithmetic::value && std::is_convertible::value + }; +}; + +#define FMT_DISABLE_CONVERSION_TO_INT(Type) \ + template <> \ + struct convert_to_int { enum { value = 0 }; } + +// Silence warnings about convering float to int. +FMT_DISABLE_CONVERSION_TO_INT(float); +FMT_DISABLE_CONVERSION_TO_INT(double); +FMT_DISABLE_CONVERSION_TO_INT(long double); + +// Disambiguates conversions to different integral types. +struct type_selector { + using char2 = struct { char a[2]; }; + static char convert(...); + static char convert(int); + static char convert(unsigned); + static char convert(long); + static char convert(unsigned long); + static char2 convert(long long); + static char2 convert(unsigned long long); + + template + static constexpr type select() { + return sizeof(convert(std::declval())) == 1 ? INT : LONG_LONG; + } +}; + template constexpr type get_type() { return std::is_reference::value || std::is_array::value ? get_type::type>() : (is_named_arg::value ? - NAMED_ARG : (convert_to_int::value ? INT : CUSTOM)); + NAMED_ARG : (convert_to_int::value ? + type_selector::select() : CUSTOM)); } template <> constexpr type get_type() { return BOOL; } @@ -549,13 +567,6 @@ class value { value(std::nullptr_t) { pointer = nullptr; } - template - value(const T &val, - typename std::enable_if::value, int>::type = 0) { - static_assert(get_type() == INT, "invalid type"); - int_value = val; - } - template value(const T &val, typename std::enable_if::value, int>::type = 0) { @@ -737,7 +748,7 @@ constexpr basic_arg make_arg(const T &value) { template inline typename std::enable_if>::type make_arg(const T &value) { - return value; + return {value}; } template diff --git a/test/format-test.cc b/test/format-test.cc index 29ae5f91..0b5e4953 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1078,6 +1078,14 @@ TEST(FormatterTest, FormatIntLocale) { EXPECT_EQ("1,234,567", format("{:n}", 1234567)); } +struct ConvertibleToLongLong { + operator long long() const { return 1LL << 32; } +}; + +TEST(FormatterTest, FormatConvertibleToLongLong) { + EXPECT_EQ("100000000", format("{:x}", ConvertibleToLongLong())); +} + TEST(FormatterTest, FormatFloat) { EXPECT_EQ("392.500000", format("{0:f}", 392.5f)); }