mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-31 11:17:35 +02:00
Add detection of wostream operator<< (#650)
This commit is contained in:
@ -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 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#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) {
|
|||||||
|
|
||||||
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> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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) {
|
|||||||
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) {
|
|||||||
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
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user