+ return fallback.value();
+}
+
+// Mixed type unwrapping always returns values, moving where possible
+template <class T,
+ class U,
+ class R = typename std::enable_if<
+ !std::is_same<T, U>::value,
+ typename std::common_type<T, U>::type>::type>
+R operator|(Optional<T>&& opt, UnwrapOr<U>&& fallback) {
+ if (T* p = opt.get_pointer()) {
+ return std::move(*p);
+ }
+ return std::move(fallback.value());
+}
+
+template <class T,
+ class U,
+ class R = typename std::enable_if<
+ !std::is_same<T, U>::value,
+ typename std::common_type<T, U>::type>::type>
+R operator|(const Optional<T>& opt, UnwrapOr<U>&& fallback) {
+ if (const T* p = opt.get_pointer()) {
+ return *p;
+ }
+ return std::move(fallback.value());
+}
+
+template <class T,
+ class U,
+ class R = typename std::enable_if<
+ !std::is_same<T, U>::value,
+ typename std::common_type<T, U>::type>::type>
+R operator|(Optional<T>&& opt, const UnwrapOr<U>& fallback) {
+ if (T* p = opt.get_pointer()) {
+ return std::move(*p);
+ }
+ return fallback.value();
+}
+
+template <class T,
+ class U,
+ class R = typename std::enable_if<
+ !std::is_same<T, U>::value,
+ typename std::common_type<T, U>::type>::type>
+R operator|(const Optional<T>& opt, const UnwrapOr<U>& fallback) {
+ if (const T* p = opt.get_pointer()) {
+ return *p;
+ }
+ return fallback.value();
+}
+
+/**
+ * Unwrap - For unwrapping folly::Optional values in a folly::gen style. Usually
+ * used through the 'unwrap' instace like so:
+ *
+ * auto best = from(scores) | max | unwrap; // may throw
+ */
+class Unwrap {};
+
+template <class T>
+T&& operator|(Optional<T>&& opt, const Unwrap&) {
+ return std::move(opt.value());
+}
+
+template <class T>
+T& operator|(Optional<T>& opt, const Unwrap&) {
+ return opt.value();
+}
+
+template <class T>
+const T& operator|(const Optional<T>& opt, const Unwrap&) {
+ return opt.value();
+}