Commit 91721caa authored by Victor Zverovich's avatar Victor Zverovich

Add detection of wostream operator<< (#650)

parent 1efc15c1
...@@ -413,7 +413,7 @@ FMT_CONSTEXPR bool is_arithmetic(type t) { ...@@ -413,7 +413,7 @@ FMT_CONSTEXPR bool is_arithmetic(type t) {
return t > internal::none_type && t <= internal::last_numeric_type; return t > internal::none_type && t <= internal::last_numeric_type;
} }
template <typename T, bool ENABLE = true> template <typename T, typename Char, bool ENABLE = true>
struct convert_to_int { struct convert_to_int {
enum { enum {
value = !std::is_arithmetic<T>::value && std::is_convertible<T, int>::value value = !std::is_arithmetic<T>::value && std::is_convertible<T, int>::value
...@@ -421,8 +421,8 @@ struct convert_to_int { ...@@ -421,8 +421,8 @@ struct convert_to_int {
}; };
#define FMT_DISABLE_CONVERSION_TO_INT(Type) \ #define FMT_DISABLE_CONVERSION_TO_INT(Type) \
template <> \ template <typename Char> \
struct convert_to_int<Type> { enum { value = 0 }; } struct convert_to_int<Type, Char> { enum { value = 0 }; }
// Silence warnings about convering float to int. // Silence warnings about convering float to int.
FMT_DISABLE_CONVERSION_TO_INT(float); FMT_DISABLE_CONVERSION_TO_INT(float);
...@@ -589,13 +589,13 @@ void make_value(const T *p) { ...@@ -589,13 +589,13 @@ void make_value(const T *p) {
template <typename C, typename T> template <typename C, typename T>
inline typename std::enable_if< inline typename std::enable_if<
convert_to_int<T>::value && std::is_enum<T>::value, convert_to_int<T, typename C::char_type>::value && std::is_enum<T>::value,
typed_value<C, int_type>>::type typed_value<C, int_type>>::type
make_value(const T &val) { return static_cast<int>(val); } make_value(const T &val) { return static_cast<int>(val); }
template <typename C, typename T> template <typename C, typename T>
inline typename std::enable_if< inline typename std::enable_if<!convert_to_int<
!convert_to_int<T>::value, typed_value<C, custom_type>>::type T, typename C::char_type>::value, typed_value<C, custom_type>>::type
make_value(const T &val) { return val; } make_value(const T &val) { return val; }
template <typename C, typename T> template <typename C, typename T>
......
...@@ -46,21 +46,22 @@ class FormatBuf : public std::basic_streambuf<Char> { ...@@ -46,21 +46,22 @@ class FormatBuf : public std::basic_streambuf<Char> {
} }
}; };
struct test_stream : std::ostream { template <typename Char>
struct test_stream : std::basic_ostream<Char> {
private: private:
struct null; struct null;
// Hide all operator<< from std::ostream. // Hide all operator<< from std::basic_ostream<Char>.
void operator<<(null); void operator<<(null);
}; };
// Disable conversion to int if T has an overloaded operator<< which is a free // Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream). // function (not a member of std::ostream).
template <typename T> template <typename T, typename Char>
class convert_to_int<T, true> { class convert_to_int<T, Char, true> {
private: private:
template <typename U> template <typename U>
static decltype( static decltype(
std::declval<test_stream&>() << std::declval<U>(), std::true_type()) std::declval<test_stream<Char>&>() << std::declval<U>(), std::true_type())
test(int); test(int);
template <typename> template <typename>
......
...@@ -53,7 +53,7 @@ std::ostream &operator<<(std::ostream &os, TestEnum) { ...@@ -53,7 +53,7 @@ std::ostream &operator<<(std::ostream &os, TestEnum) {
enum TestEnum2 {A}; enum TestEnum2 {A};
TEST(OStreamTest, Enum) { TEST(OStreamTest, Enum) {
EXPECT_FALSE(fmt::internal::convert_to_int<TestEnum>::value); EXPECT_FALSE((fmt::internal::convert_to_int<TestEnum, char>::value));
EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum())); EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum()));
EXPECT_EQ("0", fmt::format("{}", A)); EXPECT_EQ("0", fmt::format("{}", A));
} }
......
...@@ -843,15 +843,15 @@ TEST(UtilTest, ReportWindowsError) { ...@@ -843,15 +843,15 @@ TEST(UtilTest, ReportWindowsError) {
enum TestEnum2 {}; enum TestEnum2 {};
TEST(UtilTest, ConvertToInt) { TEST(UtilTest, ConvertToInt) {
EXPECT_FALSE(fmt::internal::convert_to_int<char>::value); EXPECT_FALSE((fmt::internal::convert_to_int<char, char>::value));
EXPECT_FALSE(fmt::internal::convert_to_int<const char *>::value); EXPECT_FALSE((fmt::internal::convert_to_int<const char *, char>::value));
EXPECT_TRUE(fmt::internal::convert_to_int<TestEnum2>::value); EXPECT_TRUE((fmt::internal::convert_to_int<TestEnum2, char>::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>::value); EXPECT_TRUE((fmt::internal::convert_to_int<TestEnum, char>::value));
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment