summaryrefslogtreecommitdiffstats
path: root/googletest/include/gtest
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2020-10-09 06:07:04 -0400
committerDerek Mauro <dmauro@google.com>2020-10-14 18:25:23 -0400
commit0555b0eacbc56df1fd762c6aa87bb84be9e4ce7e (patch)
tree889fe514827bc1b5b84fdce21a6b30b3a03b958b /googletest/include/gtest
parent72512aa89328f21fd18b636032c7a51d8d4ee068 (diff)
downloadgoogletest-0555b0eacbc56df1fd762c6aa87bb84be9e4ce7e.tar.gz
googletest-0555b0eacbc56df1fd762c6aa87bb84be9e4ce7e.zip
Googletest export
Improve lookup of operator<< for user types Without this fix, trying to use this class with googletest struct Foo {}; template <typename OutputStream> OutputStream& operator<<(OutputStream& os, const Foo&) { os << "TemplatedStreamableInFoo"; return os; } results in an ambiguity error between the class' operator<< and the operator<< in gtest-printers.h removed in this CL. This fix also enables implicit conversions to happen, so that e.g. we will find the base class operator<< if a subclass has no operator<< of its own. PiperOrigin-RevId: 336261221
Diffstat (limited to 'googletest/include/gtest')
-rw-r--r--googletest/include/gtest/gtest-printers.h52
1 files changed, 22 insertions, 30 deletions
diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h
index 99129a53..f697e2f0 100644
--- a/googletest/include/gtest/gtest-printers.h
+++ b/googletest/include/gtest/gtest-printers.h
@@ -192,43 +192,34 @@ 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
@@ -308,7 +299,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);
}
OpenPOWER on IntegriCloud