diff options
Diffstat (limited to 'googletest/include/gtest/gtest-printers.h')
-rw-r--r-- | googletest/include/gtest/gtest-printers.h | 103 |
1 files changed, 71 insertions, 32 deletions
diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index 308b0eb2..463f0aff 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h @@ -188,51 +188,43 @@ struct PointerPrinter { } }; -namespace internal_stream { +namespace internal_stream_operator_without_lexical_name_lookup { -struct Sentinel; -template <typename Char, typename CharTraits, typename T> -Sentinel* operator<<(::std::basic_ostream<Char, CharTraits>& os, const T& x); - -// Check if the user has a user-defined operator<< for their type. -// -// We put this in its own namespace to inject a custom operator<< that allows us -// to probe the type's operator. -// -// Note that this operator<< takes a generic std::basic_ostream<Char, -// CharTraits> type instead of the more restricted std::ostream. If -// we define it to take an std::ostream instead, we'll get an -// "ambiguous overloads" compiler error when trying to print a type -// Foo that supports streaming to std::basic_ostream<Char, -// CharTraits>, as the compiler cannot tell whether -// operator<<(std::ostream&, const T&) or -// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more -// specific. -template <typename T> -constexpr bool UseStreamOperator() { - return !std::is_same<decltype(std::declval<std::ostream&>() - << std::declval<const T&>()), - Sentinel*>::value; -} - -} // namespace internal_stream +// The presence of an operator<< here will terminate lexical scope lookup +// straight away (even though it cannot be a match because of its argument +// types). Thus, the two operator<< calls in StreamPrinter will find only ADL +// candidates. +struct LookupBlocker {}; +void operator<<(LookupBlocker, LookupBlocker); struct StreamPrinter { - template <typename T, typename = typename std::enable_if< - internal_stream::UseStreamOperator<T>()>::type> + template <typename T, + // Don't accept member pointers here. We'd print them via implicit + // conversion to bool, which isn't useful. + typename = typename std::enable_if< + !std::is_member_pointer<T>::value>::type, + // Only accept types for which we can find a streaming operator via + // ADL (possibly involving implicit conversions). + typename = decltype(std::declval<std::ostream&>() + << std::declval<const T&>())> static void PrintValue(const T& value, ::std::ostream* os) { + // Call streaming operator found by ADL, possibly with implicit conversions + // of the arguments. *os << value; } }; +} // namespace internal_stream_operator_without_lexical_name_lookup + struct ProtobufPrinter { // We print a protobuf using its ShortDebugString() when the string // doesn't exceed this many characters; otherwise we print it using // DebugString() for better readability. static const size_t kProtobufOneLinerMaxLength = 50; - template <typename T, typename = typename std::enable_if< - internal::IsAProtocolMessage<T>::value>::type> + template <typename T, + typename = typename std::enable_if< + internal::HasDebugStringAndShortDebugString<T>::value>::type> static void PrintValue(const T& value, ::std::ostream* os) { std::string pretty_str = value.ShortDebugString(); if (pretty_str.length() > kProtobufOneLinerMaxLength) { @@ -303,7 +295,8 @@ template <typename T> void PrintWithFallback(const T& value, ::std::ostream* os) { using Printer = typename FindFirstPrinter< T, void, ContainerPrinter, FunctionPointerPrinter, PointerPrinter, - StreamPrinter, ProtobufPrinter, ConvertibleToIntegerPrinter, + internal_stream_operator_without_lexical_name_lookup::StreamPrinter, + ProtobufPrinter, ConvertibleToIntegerPrinter, ConvertibleToStringViewPrinter, FallbackPrinter>::type; Printer::PrintValue(value, os); } @@ -356,6 +349,14 @@ GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); +#ifdef __cpp_char8_t +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char8_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char8_t); +#endif +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char16_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char16_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char32_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char32_t); #undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ @@ -373,6 +374,14 @@ GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); +#ifdef __cpp_char8_t +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char8_t, ::std::u8string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char8_t, ::std::u8string); +#endif +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char16_t, ::std::u16string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char16_t, ::std::u16string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char32_t, ::std::u32string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char32_t, ::std::u32string); #if GTEST_HAS_STD_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); @@ -449,6 +458,16 @@ inline void PrintTo(bool x, ::std::ostream* os) { // is implemented as an unsigned type. GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); +GTEST_API_ void PrintTo(char32_t c, ::std::ostream* os); +inline void PrintTo(char16_t c, ::std::ostream* os) { + PrintTo(ImplicitCast_<char32_t>(c), os); +} +#ifdef __cpp_char8_t +inline void PrintTo(char8_t c, ::std::ostream* os) { + PrintTo(ImplicitCast_<char32_t>(c), os); +} +#endif + // Overloads for C strings. GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); inline void PrintTo(char* s, ::std::ostream* os) { @@ -469,6 +488,26 @@ inline void PrintTo(const unsigned char* s, ::std::ostream* os) { inline void PrintTo(unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_<const void*>(s), os); } +#ifdef __cpp_char8_t +inline void PrintTo(const char8_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_<const void*>(s), os); +} +inline void PrintTo(char8_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_<const void*>(s), os); +} +#endif +inline void PrintTo(const char16_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_<const void*>(s), os); +} +inline void PrintTo(char16_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_<const void*>(s), os); +} +inline void PrintTo(const char32_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_<const void*>(s), os); +} +inline void PrintTo(char32_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_<const void*>(s), os); +} // MSVC can be configured to define wchar_t as a typedef of unsigned // short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native |