Allow log print of data units.

Bug: webrtc:9709
Change-Id: I5987a9779e645115dc1893944302a73d540bcf2f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/125680
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27578}
diff --git a/rtc_base/logging.h b/rtc_base/logging.h
index 3f48eeb..362aeae 100644
--- a/rtc_base/logging.h
+++ b/rtc_base/logging.h
@@ -186,11 +186,10 @@
   T val;
 };
 
-// TODO(bugs.webrtc.org/9278): Get rid of this specialization when callers
-// don't need it anymore. No in-tree caller does, but some external callers
-// still do.
-template <>
-struct Val<LogArgType::kStdString, std::string> {
+// Case for when we need to construct a temp string and then print that.
+// (We can't use Val<CheckArgType::kStdString, const std::string*>
+// because we need somewhere to store the temp string.)
+struct ToStringVal {
   static constexpr LogArgType Type() { return LogArgType::kStdString; }
   const std::string* GetVal() const { return &val; }
   std::string val;
@@ -265,26 +264,45 @@
 }
 #endif
 
+template <typename T, typename = void>
+struct has_to_log_string : std::false_type {};
+template <typename T>
+struct has_to_log_string<
+    T,
+    typename std::enable_if<
+        std::is_same<std::string,
+                     decltype(ToLogString(std::declval<T>()))>::value>::type>
+    : std::true_type {};
+
 // Handle arbitrary types other than the above by falling back to stringstream.
 // TODO(bugs.webrtc.org/9278): Get rid of this overload when callers don't need
 // it anymore. No in-tree caller does, but some external callers still do.
 template <
     typename T,
-    typename T1 =
-        typename std::remove_cv<typename std::remove_reference<T>::type>::type,
+    typename T1 = typename std::decay<T>::type,
     typename std::enable_if<
         std::is_class<T1>::value && !std::is_same<T1, std::string>::value &&
         !std::is_same<T1, LogMetadata>::value &&
+        !has_to_log_string<T1>::value &&
 #ifdef WEBRTC_ANDROID
         !std::is_same<T1, LogMetadataTag>::value &&
 #endif
         !std::is_same<T1, LogMetadataErr>::value>::type* = nullptr>
-Val<LogArgType::kStdString, std::string> MakeVal(const T& x) {
+ToStringVal MakeVal(const T& x) {
   std::ostringstream os;  // no-presubmit-check TODO(webrtc:8982)
   os << x;
   return {os.str()};
 }
 
+template <
+    typename T,
+    typename T1 = typename std::decay<T>::type,
+    typename std::enable_if<std::is_class<T1>::value &&
+                            has_to_log_string<T1>::value>::type* = nullptr>
+ToStringVal MakeVal(const T& x) {
+  return {ToLogString(x)};
+}
+
 void Log(const LogArgType* fmt, ...);
 
 // Ephemeral type that represents the result of the logging << operator.