about summary refs log tree commit diff
path: root/absl/base
diff options
context:
space:
mode:
Diffstat (limited to 'absl/base')
-rw-r--r--absl/base/BUILD.bazel3
-rw-r--r--absl/base/CMakeLists.txt2
-rw-r--r--absl/base/internal/invoke.h37
-rw-r--r--absl/base/invoke_test.cc21
4 files changed, 43 insertions, 20 deletions
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index e825de0c1c81..a512272adb94 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -155,6 +155,9 @@ cc_library(
     visibility = [
         "//absl:__subpackages__",
     ],
+    deps = [
+        "//absl/meta:type_traits",
+    ],
 )
 
 cc_library(
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 9ff80738db5f..cc7960e3ae88 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -133,6 +133,8 @@ absl_cc_library(
     "internal/invoke.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::type_traits
 )
 
 absl_cc_library(
diff --git a/absl/base/internal/invoke.h b/absl/base/internal/invoke.h
index 8da2869afbd7..44f13302f434 100644
--- a/absl/base/internal/invoke.h
+++ b/absl/base/internal/invoke.h
@@ -39,6 +39,8 @@
 #include <type_traits>
 #include <utility>
 
+#include "absl/meta/type_traits.h"
+
 // The following code is internal implementation detail.  See the comment at the
 // top of this file for the API documentation.
 
@@ -67,15 +69,11 @@ struct MemFunAndRef : StrippedAccept<MemFunAndRef> {
   template <typename... Args>
   struct AcceptImpl : std::false_type {};
 
-  template <typename R, typename C, typename... Params, typename Obj,
-            typename... Args>
-  struct AcceptImpl<R (C::*)(Params...), Obj, Args...>
-      : std::is_base_of<C, Obj> {};
-
-  template <typename R, typename C, typename... Params, typename Obj,
-            typename... Args>
-  struct AcceptImpl<R (C::*)(Params...) const, Obj, Args...>
-      : std::is_base_of<C, Obj> {};
+  template <typename MemFunType, typename C, typename Obj, typename... Args>
+  struct AcceptImpl<MemFunType C::*, Obj, Args...>
+      : std::integral_constant<bool, std::is_base_of<C, Obj>::value &&
+                                         absl::is_function<MemFunType>::value> {
+  };
 
   template <typename MemFun, typename Obj, typename... Args>
   static decltype((std::declval<Obj>().*
@@ -92,15 +90,11 @@ struct MemFunAndPtr : StrippedAccept<MemFunAndPtr> {
   template <typename... Args>
   struct AcceptImpl : std::false_type {};
 
-  template <typename R, typename C, typename... Params, typename Ptr,
-            typename... Args>
-  struct AcceptImpl<R (C::*)(Params...), Ptr, Args...>
-      : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
-
-  template <typename R, typename C, typename... Params, typename Ptr,
-            typename... Args>
-  struct AcceptImpl<R (C::*)(Params...) const, Ptr, Args...>
-      : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
+  template <typename MemFunType, typename C, typename Ptr, typename... Args>
+  struct AcceptImpl<MemFunType C::*, Ptr, Args...>
+      : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value &&
+                                         absl::is_function<MemFunType>::value> {
+  };
 
   template <typename MemFun, typename Ptr, typename... Args>
   static decltype(((*std::declval<Ptr>()).*
@@ -119,7 +113,9 @@ struct DataMemAndRef : StrippedAccept<DataMemAndRef> {
   struct AcceptImpl : std::false_type {};
 
   template <typename R, typename C, typename Obj>
-  struct AcceptImpl<R C::*, Obj> : std::is_base_of<C, Obj> {};
+  struct AcceptImpl<R C::*, Obj>
+      : std::integral_constant<bool, std::is_base_of<C, Obj>::value &&
+                                         !absl::is_function<R>::value> {};
 
   template <typename DataMem, typename Ref>
   static decltype(std::declval<Ref>().*std::declval<DataMem>()) Invoke(
@@ -136,7 +132,8 @@ struct DataMemAndPtr : StrippedAccept<DataMemAndPtr> {
 
   template <typename R, typename C, typename Ptr>
   struct AcceptImpl<R C::*, Ptr>
-      : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
+      : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value &&
+                                         !absl::is_function<R>::value> {};
 
   template <typename DataMem, typename Ptr>
   static decltype((*std::declval<Ptr>()).*std::declval<DataMem>()) Invoke(
diff --git a/absl/base/invoke_test.cc b/absl/base/invoke_test.cc
index 691f553791d3..9074443b3cbb 100644
--- a/absl/base/invoke_test.cc
+++ b/absl/base/invoke_test.cc
@@ -70,6 +70,10 @@ struct OverloadedFunctor {
 struct Class {
   int Method(int a, int b) { return a - b; }
   int ConstMethod(int a, int b) const { return a - b; }
+  int RefMethod(int a, int b) & { return a - b; }
+  int RefRefMethod(int a, int b) && { return a - b; }
+  int NoExceptMethod(int a, int b) noexcept { return a - b; }
+  int VolatileMethod(int a, int b) volatile { return a - b; }
 
   int member;
 };
@@ -151,8 +155,18 @@ TEST(InvokeTest, ReferenceWrapper) {
 TEST(InvokeTest, MemberFunction) {
   std::unique_ptr<Class> p(new Class);
   std::unique_ptr<const Class> cp(new Class);
+  std::unique_ptr<volatile Class> vp(new Class);
+
   EXPECT_EQ(1, Invoke(&Class::Method, p, 3, 2));
   EXPECT_EQ(1, Invoke(&Class::Method, p.get(), 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::Method, *p, 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::RefMethod, p, 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::RefMethod, p.get(), 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::RefMethod, *p, 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::RefRefMethod, std::move(*p), 3, 2));  // NOLINT
+  EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p, 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p.get(), 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, *p, 3, 2));
 
   EXPECT_EQ(1, Invoke(&Class::ConstMethod, p, 3, 2));
   EXPECT_EQ(1, Invoke(&Class::ConstMethod, p.get(), 3, 2));
@@ -162,6 +176,13 @@ TEST(InvokeTest, MemberFunction) {
   EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp.get(), 3, 2));
   EXPECT_EQ(1, Invoke(&Class::ConstMethod, *cp, 3, 2));
 
+  EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p, 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p.get(), 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *p, 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp, 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp.get(), 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *vp, 3, 2));
+
   EXPECT_EQ(1, Invoke(&Class::Method, make_unique<Class>(), 3, 2));
   EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<Class>(), 3, 2));
   EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<const Class>(), 3, 2));