Add std::variant specializations for IsOwner and IsView

Fixes: #1960
PiperOrigin-RevId: 951017341
Change-Id: If8de7073695152947aa93e0d5a3800dac6e353b6
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index be55e52..d12300f 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -41,6 +41,7 @@
 #include <string_view>
 #include <type_traits>
 #include <utility>
+#include <variant>
 #include <vector>
 
 #include "absl/base/attributes.h"
@@ -583,6 +584,14 @@
 template <typename T, typename Alloc>
 struct IsOwner<std::vector<T, Alloc>> : std::true_type {};
 
+template <typename... T>
+struct IsOwner<std::variant<T...>>
+    : std::bool_constant<(sizeof...(T) > 0) &&
+                         // Uses a C++17 fold expression where '...' unpacks the
+                         // parameter pack T, and 'true &&' provides the base
+                         // case for the logical AND operation across all types.
+                         (true && ... && IsOwner<T>::value)> {};
+
 // Detects if a class's definition has declared itself to be a view by declaring
 //   using absl_internal_is_view = std::true_type;
 // as a member.
@@ -620,6 +629,14 @@
 template <typename Char, typename Traits>
 struct IsView<std::basic_string_view<Char, Traits>> : std::true_type {};
 
+template <typename... T>
+struct IsView<std::variant<T...>>
+    : std::bool_constant<(sizeof...(T) > 0) &&
+                         // Uses a C++17 fold expression where '...' unpacks the
+                         // parameter pack T, and 'true &&' provides the base
+                         // case for the logical AND operation across all types.
+                         (true && ... && IsView<T>::value)> {};
+
 #ifdef __cpp_lib_span
 template <typename T>
 struct IsView<std::span<T>> : std::true_type {};
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc
index 9734fc1..8e5f90d 100644
--- a/absl/meta/type_traits_test.cc
+++ b/absl/meta/type_traits_test.cc
@@ -19,6 +19,7 @@
 #include <string_view>
 #include <type_traits>
 #include <utility>
+#include <variant>
 #include <vector>
 
 #include "gtest/gtest.h"
@@ -32,6 +33,11 @@
 using ::testing::StaticAssertTypeEq;
 
 template <typename T>
+using IsViewAndNotOwner =
+    std::conjunction<absl::type_traits_internal::IsView<T>,
+                     std::negation<absl::type_traits_internal::IsOwner<T>>>;
+
+template <typename T>
 using IsOwnerAndNotView =
     std::conjunction<absl::type_traits_internal::IsOwner<T>,
                       std::negation<absl::type_traits_internal::IsView<T>>>;
@@ -50,6 +56,23 @@
 static_assert(!IsOwnerAndNotView<std::wstring_view>::value,
               "wstring_view is a view, not an owner");
 
+static_assert(!IsOwnerAndNotView<std::variant<>>::value,
+              "empty variant is not an owner");
+static_assert(!IsViewAndNotOwner<std::variant<>>::value,
+              "empty variant is not a view");
+
+static_assert(IsOwnerAndNotView<std::variant<std::string, std::vector<char>,
+                                             std::vector<int>>>::value,
+              "aggregate of owners is an owner");
+static_assert(
+    IsViewAndNotOwner<std::variant<std::wstring_view, std::string_view>>::value,
+    "aggregate of views is an view");
+
+static_assert(!IsOwnerAndNotView<std::variant<const char*, std::string>>::value,
+              "variant of mixed-ownership types is not considered an owner");
+static_assert(!IsViewAndNotOwner<std::variant<const char*, std::string>>::value,
+              "variant of mixed-ownership types is not considered a view");
+
 template <class T, class U>
 struct simple_pair {
   T first;