4040#include " absl/log/internal/nullstream.h"
4141#include " absl/log/internal/strip.h"
4242#include " absl/strings/has_absl_stringify.h"
43+ #include " absl/strings/has_ostream_operator.h"
4344#include " absl/strings/string_view.h"
4445
4546// `ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL` wraps string literals that
@@ -357,21 +358,12 @@ std::enable_if_t<HasAbslStringify<T>::value,
357358 StringifyToStreamWrapper<T>>
358359Detect (...); // Ellipsis has lowest preference when int passed.
359360
360- // is_streamable is true for types that have an output stream operator<<.
361- template <class T , class = void >
362- struct is_streamable : std::false_type {};
363-
364- template <class T >
365- struct is_streamable <T, std::void_t <decltype (std::declval<std::ostream&>()
366- << std::declval<T>())>>
367- : std::true_type {};
368-
369361// This overload triggers when T is neither possible to print nor an enum.
370362template <typename T>
371363std::enable_if_t <std::negation_v<std::disjunction<
372364 std::is_convertible<T, int >, std::is_enum<T>,
373365 std::is_pointer<T>, std::is_same<T, std::nullptr_t >,
374- is_streamable <T>, HasAbslStringify<T>>>,
366+ HasOstreamOperator <T>, HasAbslStringify<T>>>,
375367 UnprintableWrapper>
376368Detect (...);
377369
@@ -382,9 +374,10 @@ Detect(...);
382374// one backed by another integer is converted to (u)int64_t.
383375template <typename T>
384376std::enable_if_t <
385- std::conjunction_v<
386- std::is_enum<T>, std::negation<std::is_convertible<T, int >>,
387- std::negation<is_streamable<T>>, std::negation<HasAbslStringify<T>>>,
377+ std::conjunction_v<std::is_enum<T>,
378+ std::negation<std::is_convertible<T, int >>,
379+ std::negation<HasOstreamOperator<T>>,
380+ std::negation<HasAbslStringify<T>>>,
388381 std::conditional_t <
389382 std::is_same_v<std::underlying_type_t <T>, bool > ||
390383 std::is_same_v<std::underlying_type_t <T>, char > ||
0 commit comments