Replace a bunch of craft with type_traits, take 2

This commit is contained in:
Victor Zverovich
2018-01-22 18:56:53 -08:00
parent 21429c8646
commit a93270fd60
3 changed files with 24 additions and 44 deletions

View File

@ -338,36 +338,11 @@ inline void require_wchar() {
"formatting of wide characters into a narrow output is disallowed"); "formatting of wide characters into a narrow output is disallowed");
} }
using yes = char[1]; template <typename T, bool ENABLE = true>
using no = char[2];
yes &convert(unsigned long long);
no &convert(...);
template<typename T, bool ENABLE_CONVERSION>
struct convert_to_int_impl {
enum { value = ENABLE_CONVERSION };
};
template<typename T, bool ENABLE_CONVERSION>
struct convert_to_int_impl2 {
enum { value = false };
};
template<typename T>
struct convert_to_int_impl2<T, true> {
enum {
// Don't convert arithmetic types.
value = convert_to_int_impl<T, !std::is_arithmetic<T>::value>::value
};
};
template<typename T>
struct convert_to_int { struct convert_to_int {
enum { enum {
enable_conversion = sizeof(convert(std::declval<T>())) == sizeof(yes) value = !std::is_arithmetic<T>::value && std::is_convertible<T, int>::value
}; };
enum { value = convert_to_int_impl2<T, enable_conversion>::value };
}; };
#define FMT_DISABLE_CONVERSION_TO_INT(Type) \ #define FMT_DISABLE_CONVERSION_TO_INT(Type) \

View File

@ -47,23 +47,28 @@ class FormatBuf : public std::basic_streambuf<Char> {
} }
}; };
yes &convert(std::ostream &); struct test_stream : std::ostream {
private:
struct DummyStream : std::ostream { struct null;
DummyStream(); // Suppress a bogus warning in MSVC. // Hide all operator<< from std::ostream.
// Hide all operator<< overloads from std::ostream. void operator<<(null);
void operator<<(null<>);
}; };
no &operator<<(std::ostream &, int); // Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream).
template <typename T>
class convert_to_int<T, true> {
private:
template <typename U>
static decltype(
std::declval<test_stream&>() << std::declval<U>(), std::true_type())
test(int);
template<typename T> template <typename>
struct convert_to_int_impl<T, true> { static std::false_type test(...);
// Convert to int only if T doesn't have an overloaded operator<<.
enum { public:
value = sizeof(convert(std::declval<DummyStream&>() << std::declval<T>())) static const bool value = !decltype(test<T>(0))::value;
== sizeof(no)
};
}; };
// Write the content of buf to os. // Write the content of buf to os.

View File

@ -827,15 +827,15 @@ TEST(UtilTest, ReportWindowsError) {
enum TestEnum2 {}; enum TestEnum2 {};
TEST(UtilTest, ConvertToInt) { TEST(UtilTest, ConvertToInt) {
EXPECT_TRUE(fmt::internal::convert_to_int<char>::enable_conversion); EXPECT_FALSE(fmt::internal::convert_to_int<char>::value);
EXPECT_FALSE(fmt::internal::convert_to_int<const char *>::enable_conversion); EXPECT_FALSE(fmt::internal::convert_to_int<const char *>::value);
EXPECT_TRUE(fmt::internal::convert_to_int<TestEnum2>::value); EXPECT_TRUE(fmt::internal::convert_to_int<TestEnum2>::value);
} }
#if FMT_USE_ENUM_BASE #if FMT_USE_ENUM_BASE
enum TestEnum : char {TestValue}; enum TestEnum : char {TestValue};
TEST(UtilTest, IsEnumConvertibleToInt) { TEST(UtilTest, IsEnumConvertibleToInt) {
EXPECT_TRUE(fmt::internal::convert_to_int<TestEnum>::enable_conversion); EXPECT_TRUE(fmt::internal::convert_to_int<TestEnum>::value);
} }
#endif #endif