ExceptionWrapper::with_exception variant, deducing exception type from functor type
authorYedidya Feldblum <yfeldblum@fb.com>
Wed, 25 Nov 2015 02:27:46 +0000 (18:27 -0800)
committerfacebook-github-bot-0 <folly-bot@fb.com>
Wed, 25 Nov 2015 03:20:21 +0000 (19:20 -0800)
Summary: [Folly] `ExceptionWrapper::with_exception` variant deducing exception type from functor type.

From the `README.md`:

    // TODO(jsedgwick) infer exception type from the type of the function

Reviewed By: Gownta

Differential Revision: D2685579

fb-gh-sync-id: 158bcd030019f28b4f392d17167ab0bd67cc1edb

folly/ExceptionWrapper.h
folly/test/ExceptionWrapperTest.cpp

index bc8c9758d1a921e47c2343a29befcc11b078fb6b..70eb996bd433a7c906267492aa77471db6dc4c68 100644 (file)
@@ -223,6 +223,18 @@ class exception_wrapper {
     return false;
   }
 
+  template <class F>
+  bool with_exception(F&& f) {
+    using arg_type = typename functor_traits<F>::arg_type_decayed;
+    return with_exception<arg_type>(std::forward<F>(f));
+  }
+
+  template <class F>
+  bool with_exception(F&& f) const {
+    using arg_type = typename functor_traits<F>::arg_type_decayed;
+    return with_exception<const arg_type>(std::forward<F>(f));
+  }
+
   // If this exception wrapper wraps an exception of type Ex, with_exception
   // will call f with the wrapped exception as an argument and return true, and
   // will otherwise return false.
@@ -310,6 +322,18 @@ protected:
   friend exception_wrapper make_exception_wrapper(Args&&... args);
 
 private:
+  template <typename F>
+  struct functor_traits {
+    template <typename T>
+    struct impl;
+    template <typename C, typename R, typename A>
+    struct impl<R(C::*)(A)> { using arg_type = A; };
+    template <typename C, typename R, typename A>
+    struct impl<R(C::*)(A) const> { using arg_type = A; };
+    using arg_type = typename impl<decltype(&F::operator())>::arg_type;
+    using arg_type_decayed = typename std::decay<arg_type>::type;
+  };
+
   // What makes this useful is that T can be exception_wrapper* or
   // const exception_wrapper*, and the compiler will use the
   // instantiation which works with F.
index 723dff047a05ef2d59749630cf4a622c0972389a..61395df7ca1d53cd965767279ad2d63fb908636a 100644 (file)
@@ -203,6 +203,34 @@ TEST(ExceptionWrapper, with_exception_test) {
 */
 }
 
+TEST(ExceptionWrapper, with_exception_deduction) {
+  auto ew = make_exception_wrapper<std::runtime_error>("hi");
+  EXPECT_TRUE(ew.with_exception([](std::runtime_error&) {}));
+  EXPECT_TRUE(ew.with_exception([](std::exception&) {}));
+  EXPECT_FALSE(ew.with_exception([](std::logic_error&) {}));
+}
+
+TEST(ExceptionWrapper, with_exception_deduction_const) {
+  auto ew = make_exception_wrapper<std::runtime_error>("hi");
+  EXPECT_TRUE(ew.with_exception([](const std::runtime_error&) {}));
+  EXPECT_TRUE(ew.with_exception([](const std::exception&) {}));
+  EXPECT_FALSE(ew.with_exception([](const std::logic_error&) {}));
+}
+
+TEST(ExceptionWrapper, with_exception_deduction_const_const) {
+  const auto cew = make_exception_wrapper<std::runtime_error>("hi");
+  EXPECT_TRUE(cew.with_exception([](const std::runtime_error&) {}));
+  EXPECT_TRUE(cew.with_exception([](const std::exception&) {}));
+  EXPECT_FALSE(cew.with_exception([](const std::logic_error&) {}));
+}
+
+TEST(ExceptionWrapper, with_exception_deduction_returning) {
+  auto ew = make_exception_wrapper<std::runtime_error>("hi");
+  EXPECT_TRUE(ew.with_exception([](std::runtime_error&) { return 3; }));
+  EXPECT_TRUE(ew.with_exception([](std::exception&) { return "hello"; }));
+  EXPECT_FALSE(ew.with_exception([](std::logic_error&) { return nullptr; }));
+}
+
 TEST(ExceptionWrapper, non_std_exception_test) {
   int expected = 17;