blob: 52be7cc9240e3d282871693fe0f75c4f928f54fe [file] [log] [blame] [edit]
From 62bba06a487ff8ec300847d916705cddfdbc2719 Mon Sep 17 00:00:00 2001
From: Nathan Muggli <nmuggli@google.com>
Date: Wed, 2 Aug 2023 10:26:12 -0600
Subject: [PATCH] Revert "Land intentional C++20 use in base/."
This reverts commit c5acc58e7bebe5de213668909a9414b97c58c9c7.
patch-name: backward-compatibility-1400-Revert-Land-intentional-C-20-use-in-base.patch
Change-Id: Iab4e3adeb005025fdecdfeef6786662692aa11c0
---
base/check_op.h | 9 +++--
base/strings/to_string.h | 34 +++++++++-------
base/strings/to_string_unittest.cc | 16 ++------
base/types/strong_alias.h | 2 +-
base/types/strong_alias_unittest.cc | 4 +-
base/types/supports_ostream_operator.h | 10 +++--
.../supports_ostream_operator_unittest.cc | 39 ++++++++++---------
7 files changed, 61 insertions(+), 53 deletions(-)
diff --git a/base/check_op.h b/base/check_op.h
index 53eb17b67b..d4e3bf7f6d 100644
--- a/base/check_op.h
+++ b/base/check_op.h
@@ -70,7 +70,7 @@ BASE_EXPORT char* StreamValToStr(const void* v,
template <typename T>
inline typename std::enable_if<
- base::internal::SupportsOstreamOperator<const T&> &&
+ base::internal::SupportsOstreamOperator<const T&>::value &&
!std::is_function_v<typename std::remove_pointer<T>::type>,
char*>::type
CheckOpValueStr(const T& v) {
@@ -96,8 +96,8 @@ CheckOpValueStr(const T& v) {
// Overload for types that have no operator<< but do have .ToString() defined.
template <typename T>
inline typename std::enable_if<
- !base::internal::SupportsOstreamOperator<const T&> &&
- base::internal::SupportsToString<const T&>,
+ !base::internal::SupportsOstreamOperator<const T&>::value &&
+ base::internal::SupportsToString<const T&>::value,
char*>::type
CheckOpValueStr(const T& v) {
// .ToString() may not return a std::string, e.g. blink::WTF::String.
@@ -121,7 +121,8 @@ CheckOpValueStr(const T& v) {
// (i.e. scoped enums where no operator<< overload was declared).
template <typename T>
inline typename std::enable_if<
- !base::internal::SupportsOstreamOperator<const T&> && std::is_enum_v<T>,
+ !base::internal::SupportsOstreamOperator<const T&>::value &&
+ std::is_enum_v<T>,
char*>::type
CheckOpValueStr(const T& v) {
return CheckOpValueStr(
diff --git a/base/strings/to_string.h b/base/strings/to_string.h
index eae7b944cd..911622db47 100644
--- a/base/strings/to_string.h
+++ b/base/strings/to_string.h
@@ -23,8 +23,11 @@ std::string ToString(const Ts&... values);
namespace internal {
+template <typename T, typename = void>
+struct SupportsToString : std::false_type {};
template <typename T>
-concept SupportsToString = requires(const T& t) { t.ToString(); };
+struct SupportsToString<T, decltype(void(std::declval<T>().ToString()))>
+ : std::true_type {};
// I/O manipulators are function pointers, but should be sent directly to the
// `ostream` instead of being cast to `const void*` like other function
@@ -56,17 +59,19 @@ struct ToStringHelper {
// Most streamables.
template <typename T>
-struct ToStringHelper<T,
- std::enable_if_t<SupportsOstreamOperator<const T&> &&
- !WillBeIncorrectlyStreamedAsBool<T>>> {
+struct ToStringHelper<
+ T,
+ std::enable_if_t<SupportsOstreamOperator<const T&>::value &&
+ !WillBeIncorrectlyStreamedAsBool<T>>> {
static void Stringify(const T& v, std::ostringstream& ss) { ss << v; }
};
// Functions and function pointers.
template <typename T>
-struct ToStringHelper<T,
- std::enable_if_t<SupportsOstreamOperator<const T&> &&
- WillBeIncorrectlyStreamedAsBool<T>>> {
+struct ToStringHelper<
+ T,
+ std::enable_if_t<SupportsOstreamOperator<const T&>::value &&
+ WillBeIncorrectlyStreamedAsBool<T>>> {
static void Stringify(const T& v, std::ostringstream& ss) {
ToStringHelper<const void*>::Stringify(reinterpret_cast<const void*>(v),
ss);
@@ -75,9 +80,10 @@ struct ToStringHelper<T,
// Non-streamables that have a `ToString` member.
template <typename T>
-struct ToStringHelper<T,
- std::enable_if_t<!SupportsOstreamOperator<const T&> &&
- SupportsToString<const T&>>> {
+struct ToStringHelper<
+ T,
+ std::enable_if_t<!SupportsOstreamOperator<const T&>::value &&
+ SupportsToString<const T&>::value>> {
static void Stringify(const T& v, std::ostringstream& ss) {
// .ToString() may not return a std::string, e.g. blink::WTF::String.
ToStringHelper<decltype(v.ToString())>::Stringify(v.ToString(), ss);
@@ -89,7 +95,8 @@ struct ToStringHelper<T,
template <typename T>
struct ToStringHelper<
T,
- std::enable_if_t<!SupportsOstreamOperator<const T&> && std::is_enum_v<T>>> {
+ std::enable_if_t<!SupportsOstreamOperator<const T&>::value &&
+ std::is_enum_v<T>>> {
static void Stringify(const T& v, std::ostringstream& ss) {
using UT = typename std::underlying_type_t<T>;
ToStringHelper<UT>::Stringify(static_cast<UT>(v), ss);
@@ -120,8 +127,9 @@ struct ToStringHelper<std::tuple<T...>> {
template <typename... Ts>
std::string ToString(const Ts&... values) {
std::ostringstream ss;
- (..., internal::ToStringHelper<remove_cvref_t<decltype(values)>>::Stringify(
- values, ss));
+ (internal::ToStringHelper<remove_cvref_t<decltype(values)>>::Stringify(values,
+ ss),
+ ...);
return ss.str();
}
diff --git a/base/strings/to_string_unittest.cc b/base/strings/to_string_unittest.cc
index dca285ff52..3cb3c22356 100644
--- a/base/strings/to_string_unittest.cc
+++ b/base/strings/to_string_unittest.cc
@@ -20,22 +20,14 @@ class HasToString {
};
// .ToString() support on structs.
-static_assert(!internal::SupportsToString<NotStringifiable>,
+static_assert(!internal::SupportsToString<NotStringifiable>::value,
"value without ToString() shouldn't be marked SupportsToString");
-static_assert(!internal::SupportsToString<NotStringifiable&>,
- "& without ToString() shouldn't be marked SupportsToString");
-static_assert(!internal::SupportsToString<const NotStringifiable&>,
+static_assert(!internal::SupportsToString<const NotStringifiable&>::value,
"const& without ToString() shouldn't be marked SupportsToString");
-static_assert(!internal::SupportsToString<NotStringifiable&&>,
- "&& without ToString() shouldn't be marked SupportsToString");
-static_assert(internal::SupportsToString<HasToString>,
+static_assert(internal::SupportsToString<HasToString>::value,
"value with ToString() should be marked SupportsToString");
-static_assert(internal::SupportsToString<HasToString&>,
- "& with ToString() should be marked SupportsToString");
-static_assert(internal::SupportsToString<const HasToString&>,
+static_assert(internal::SupportsToString<const HasToString&>::value,
"const& with ToString() should be marked SupportsToString");
-static_assert(internal::SupportsToString<HasToString&&>,
- "&& with ToString() should be marked SupportsToString");
TEST(ToStringTest, Streamable) {
// Types with built-in <<.
diff --git a/base/types/strong_alias.h b/base/types/strong_alias.h
index 79d39808b0..7a4872a4a0 100644
--- a/base/types/strong_alias.h
+++ b/base/types/strong_alias.h
@@ -154,7 +154,7 @@ class StrongAlias {
template <typename TagType,
typename UnderlyingType,
typename = std::enable_if_t<
- internal::SupportsOstreamOperator<UnderlyingType>>>
+ internal::SupportsOstreamOperator<UnderlyingType>::value>>
std::ostream& operator<<(std::ostream& stream,
const StrongAlias<TagType, UnderlyingType>& alias) {
return stream << alias.value();
diff --git a/base/types/strong_alias_unittest.cc b/base/types/strong_alias_unittest.cc
index e69cf7b704..b211d3b474 100644
--- a/base/types/strong_alias_unittest.cc
+++ b/base/types/strong_alias_unittest.cc
@@ -371,7 +371,7 @@ TEST(StrongAliasTest, EnsureConstexpr) {
void StreamOperatorExists() {
// Aliases of ints should be streamable because ints are streamable.
using StreamableAlias = StrongAlias<class IntTag, int>;
- static_assert(internal::SupportsOstreamOperator<StreamableAlias>);
+ static_assert(internal::SupportsOstreamOperator<StreamableAlias>::value);
// Aliases of a class which does not expose a stream operator should
// themselves not be streamable.
@@ -380,7 +380,7 @@ void StreamOperatorExists() {
Scope() = default;
};
using NonStreamableAlias = StrongAlias<class ScopeTag, Scope>;
- static_assert(!internal::SupportsOstreamOperator<NonStreamableAlias>);
+ static_assert(!internal::SupportsOstreamOperator<NonStreamableAlias>::value);
}
#if BUILDFLAG(ENABLE_BASE_TRACING)
diff --git a/base/types/supports_ostream_operator.h b/base/types/supports_ostream_operator.h
index 7e0100f970..0803db4862 100644
--- a/base/types/supports_ostream_operator.h
+++ b/base/types/supports_ostream_operator.h
@@ -11,13 +11,17 @@
namespace base::internal {
-// Detects whether using operator<< would work.
+// Uses expression SFINAE to detect whether using operator<< would work.
//
// Note that the above #include of <ostream> is necessary to guarantee
// consistent results here for basic types.
+template <typename T, typename = void>
+struct SupportsOstreamOperator : std::false_type {};
template <typename T>
-concept SupportsOstreamOperator =
- requires(const T& t, std::ostream& os) { os << t; };
+struct SupportsOstreamOperator<T,
+ decltype(void(std::declval<std::ostream&>()
+ << std::declval<T>()))>
+ : std::true_type {};
} // namespace base::internal
diff --git a/base/types/supports_ostream_operator_unittest.cc b/base/types/supports_ostream_operator_unittest.cc
index 31e2628962..0f8c3a09d9 100644
--- a/base/types/supports_ostream_operator_unittest.cc
+++ b/base/types/supports_ostream_operator_unittest.cc
@@ -26,40 +26,43 @@ std::ostream& operator<<(std::ostream& os, const StructWithOperator& v) {
}
// A few standard types that definitely support printing.
-static_assert(internal::SupportsOstreamOperator<int>,
+static_assert(internal::SupportsOstreamOperator<int>::value,
"ints should be printable");
-static_assert(internal::SupportsOstreamOperator<const char*>,
+static_assert(internal::SupportsOstreamOperator<const char*>::value,
"C strings should be printable");
-static_assert(internal::SupportsOstreamOperator<std::string>,
+static_assert(internal::SupportsOstreamOperator<std::string>::value,
"std::string should be printable");
// Various kinds of enums operator<< support.
-static_assert(internal::SupportsOstreamOperator<SimpleEnum>,
+static_assert(internal::SupportsOstreamOperator<SimpleEnum>::value,
"simple enum should be printable by value");
-static_assert(internal::SupportsOstreamOperator<const SimpleEnum&>,
+static_assert(internal::SupportsOstreamOperator<const SimpleEnum&>::value,
"simple enum should be printable by const ref");
-static_assert(internal::SupportsOstreamOperator<EnumWithExplicitType>,
+static_assert(internal::SupportsOstreamOperator<EnumWithExplicitType>::value,
"enum with explicit type should be printable by value");
-static_assert(internal::SupportsOstreamOperator<const EnumWithExplicitType&>,
- "enum with explicit type should be printable by const ref");
-static_assert(!internal::SupportsOstreamOperator<ScopedEnum>,
+static_assert(
+ internal::SupportsOstreamOperator<const EnumWithExplicitType&>::value,
+ "enum with explicit type should be printable by const ref");
+static_assert(!internal::SupportsOstreamOperator<ScopedEnum>::value,
"scoped enum should not be printable by value");
-static_assert(!internal::SupportsOstreamOperator<const ScopedEnum&>,
+static_assert(!internal::SupportsOstreamOperator<const ScopedEnum&>::value,
"simple enum should not be printable by const ref");
-static_assert(internal::SupportsOstreamOperator<ScopedEnumWithOperator>,
+static_assert(internal::SupportsOstreamOperator<ScopedEnumWithOperator>::value,
"scoped enum with operator<< should be printable by value");
-static_assert(internal::SupportsOstreamOperator<const ScopedEnumWithOperator&>,
- "scoped enum with operator<< should be printable by const ref");
+static_assert(
+ internal::SupportsOstreamOperator<const ScopedEnumWithOperator&>::value,
+ "scoped enum with operator<< should be printable by const ref");
// operator<< support on structs.
-static_assert(!internal::SupportsOstreamOperator<SimpleStruct>,
+static_assert(!internal::SupportsOstreamOperator<SimpleStruct>::value,
"simple struct should not be printable by value");
-static_assert(!internal::SupportsOstreamOperator<const SimpleStruct&>,
+static_assert(!internal::SupportsOstreamOperator<const SimpleStruct&>::value,
"simple struct should not be printable by const ref");
-static_assert(internal::SupportsOstreamOperator<StructWithOperator>,
+static_assert(internal::SupportsOstreamOperator<StructWithOperator>::value,
"struct with operator<< should be printable by value");
-static_assert(internal::SupportsOstreamOperator<const StructWithOperator&>,
- "struct with operator<< should be printable by const ref");
+static_assert(
+ internal::SupportsOstreamOperator<const StructWithOperator&>::value,
+ "struct with operator<< should be printable by const ref");
} // namespace
} // namespace base
--
2.42.0.758.gaed0368e0e-goog