allow passing function pointers to Future::onError()
authorAdam Simpkins <simpkins@fb.com>
Thu, 22 Jun 2017 20:39:56 +0000 (13:39 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Thu, 22 Jun 2017 20:51:21 +0000 (13:51 -0700)
Summary:
Add appropriate specializations for detail::Extract() so that you can pass a
plain function pointer to `onError()`.  Previously the code only worked with
member function pointers and functor-style objects.

Reviewed By: yfeldblum, wez

Differential Revision: D5286773

fbshipit-source-id: 67b44d1d7573eb1da501475045fd24ad4ab1c074

folly/futures/Future-pre.h
folly/futures/test/FutureTest.cpp

index e3f5021eaf4b86d00b70da6d5e21adb954513e71..bcae5b0819d528245c0f1da99f85e4baa6f539f8 100644 (file)
@@ -119,6 +119,22 @@ struct Extract<R(Class::*)(Args...)> {
   typedef typename ArgType<Args...>::FirstArg FirstArg;
 };
 
+template <typename R, typename... Args>
+struct Extract<R (*)(Args...)> {
+  typedef isFuture<R> ReturnsFuture;
+  typedef Future<typename ReturnsFuture::Inner> Return;
+  typedef typename ReturnsFuture::Inner RawReturn;
+  typedef typename ArgType<Args...>::FirstArg FirstArg;
+};
+
+template <typename R, typename... Args>
+struct Extract<R (&)(Args...)> {
+  typedef isFuture<R> ReturnsFuture;
+  typedef Future<typename ReturnsFuture::Inner> Return;
+  typedef typename ReturnsFuture::Inner RawReturn;
+  typedef typename ArgType<Args...>::FirstArg FirstArg;
+};
+
 // gcc-4.8 refuses to capture a function reference in a lambda. This can be
 // mitigated by casting them to function pointer types first. The following
 // helper is used in Future.h to achieve that where necessary.
index 3bfb8e331fa986d86d67fb2f89956afa53cc005c..3322d2f4af52b5d40b028f99c2f5bbe138b0ddd2 100644 (file)
@@ -76,6 +76,15 @@ TEST(Future, makeFutureWithUnit) {
   EXPECT_EQ(1, count);
 }
 
+namespace {
+Future<int> onErrorHelperEggs(const eggs_t&) {
+  return makeFuture(10);
+}
+Future<int> onErrorHelperGeneric(const std::exception&) {
+  return makeFuture(20);
+}
+}
+
 TEST(Future, onError) {
   bool theFlag = false;
   auto flag = [&]{ theFlag = true; };
@@ -191,6 +200,28 @@ TEST(Future, onError) {
     EXPECT_NO_THROW(f.value());
   }
 
+  // Function pointer
+  {
+    auto f = makeFuture()
+                 .then([]() -> int { throw eggs; })
+                 .onError(onErrorHelperEggs)
+                 .onError(onErrorHelperGeneric);
+    EXPECT_EQ(10, f.value());
+  }
+  {
+    auto f = makeFuture()
+                 .then([]() -> int { throw std::runtime_error("test"); })
+                 .onError(onErrorHelperEggs)
+                 .onError(onErrorHelperGeneric);
+    EXPECT_EQ(20, f.value());
+  }
+  {
+    auto f = makeFuture()
+                 .then([]() -> int { throw std::runtime_error("test"); })
+                 .onError(onErrorHelperEggs);
+    EXPECT_THROW(f.value(), std::runtime_error);
+  }
+
   // No throw
   {
     auto f = makeFuture()