return std::exception_ptr();
}
- private:
+ protected:
std::shared_ptr<std::exception> item_;
void (*throwfn_)(std::exception*);
return ew;
}
+/*
+ * try_and_catch is a simple replacement for try {} catch(){} that allows you to
+ * specify which derived exceptions you would like to catch and store in an
+ * exception_wrapper.
+ *
+ * Because we cannot build an equivalent of std::current_exception(), we need
+ * to catch every derived exception that we are interested in catching.
+ *
+ * Exceptions should be listed in the reverse order that you would write your
+ * catch statements (that is, std::exception& should be first).
+ *
+ * NOTE: Although implemented as a derived class (for syntactic delight), don't
+ * be confused - you should not pass around try_and_catch objects!
+ *
+ * Example Usage:
+ *
+ * // This catches my runtime_error and if I call throwException() on ew, it
+ * // will throw a runtime_error
+ * auto ew = folly::try_and_catch<std::exception, std::runtime_error>([=]() {
+ * if (badThingHappens()) {
+ * throw std::runtime_error("ZOMG!");
+ * }
+ * });
+ *
+ * // This will catch the exception and if I call throwException() on ew, it
+ * // will throw a std::exception
+ * auto ew = folly::try_and_catch<std::exception, std::runtime_error>([=]() {
+ * if (badThingHappens()) {
+ * throw std::exception();
+ * }
+ * });
+ *
+ * // This will not catch the exception and it will be thrown.
+ * auto ew = folly::try_and_catch<std::runtime_error>([=]() {
+ * if (badThingHappens()) {
+ * throw std::exception();
+ * }
+ * });
+ */
+
+template <typename... Exceptions>
+class try_and_catch;
+
+template <typename LastException, typename... Exceptions>
+class try_and_catch<LastException, Exceptions...> :
+ public try_and_catch<Exceptions...> {
+ public:
+ template <typename F>
+ explicit try_and_catch(F&& fn) : Base() {
+ call_fn(fn);
+ }
+
+ protected:
+ typedef try_and_catch<Exceptions...> Base;
+
+ try_and_catch() : Base() {}
+
+ template <typename F>
+ void call_fn(F&& fn) {
+ try {
+ Base::call_fn(std::move(fn));
+ } catch (const LastException& e) {
+ this->item_ = std::make_shared<LastException>(e);
+ this->throwfn_ = folly::detail::Thrower<LastException>::doThrow;
+ }
+ }
+};
+
+template<>
+class try_and_catch<> : public exception_wrapper {
+ public:
+ try_and_catch() {}
+
+ protected:
+ template <typename F>
+ void call_fn(F&& fn) {
+ fn();
+ }
+};
}
#endif
ew = make_exception_wrapper<std::runtime_error>("payload");
EXPECT_TRUE(bool(ew));
}
+
+TEST(ExceptionWrapper, try_and_catch_test) {
+ std::string expected = "payload";
+
+ // Catch rightmost matching exception type
+ exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
+ [=]() {
+ throw std::runtime_error(expected);
+ });
+ EXPECT_TRUE(ew.get());
+ EXPECT_EQ(ew.get()->what(), expected);
+ auto rep = dynamic_cast<std::runtime_error*>(ew.get());
+ EXPECT_TRUE(rep);
+
+ // Changing order is like catching in wrong order. Beware of this in your
+ // code.
+ auto ew2 = try_and_catch<std::runtime_error, std::exception>([=]() {
+ throw std::runtime_error(expected);
+ });
+ EXPECT_TRUE(ew2.get());
+ // We are catching a std::exception, not std::runtime_error.
+ EXPECT_NE(ew2.get()->what(), expected);
+ rep = dynamic_cast<std::runtime_error*>(ew2.get());
+ EXPECT_FALSE(rep);
+
+ // Catches even if not rightmost.
+ auto ew3 = try_and_catch<std::exception, std::runtime_error>([]() {
+ throw std::exception();
+ });
+ EXPECT_TRUE(ew3.get());
+ EXPECT_NE(ew3.get()->what(), expected);
+ rep = dynamic_cast<std::runtime_error*>(ew3.get());
+ EXPECT_FALSE(rep);
+
+ // If does not catch, throws.
+ EXPECT_THROW(
+ try_and_catch<std::runtime_error>([]() {
+ throw std::exception();
+ }),
+ std::exception);
+}