summaryrefslogtreecommitdiff
path: root/src/mongo/stdx
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2020-10-30 04:34:18 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-10-31 05:56:16 +0000
commit6672b855264f466cc1ea7c911ea1942aabb42f14 (patch)
tree3ab98f2f3671decf4cd881f380e74b5c329a01d6 /src/mongo/stdx
parent5a78e037019ed5f23a6581cd0c61e8de02fedae0 (diff)
downloadmongo-6672b855264f466cc1ea7c911ea1942aabb42f14.tar.gz
SERVER-51888 stdx::is_detected and related traits
ReplSetConfigBase now needs a public serialize to work around MSVC bug
Diffstat (limited to 'src/mongo/stdx')
-rw-r--r--src/mongo/stdx/type_traits.h78
1 files changed, 78 insertions, 0 deletions
diff --git a/src/mongo/stdx/type_traits.h b/src/mongo/stdx/type_traits.h
index 2ea2c0bc176..13938e32114 100644
--- a/src/mongo/stdx/type_traits.h
+++ b/src/mongo/stdx/type_traits.h
@@ -141,3 +141,81 @@ struct is_invocable_r
} // namespace stdx
} // namespace mongo
+
+// TS2's `std::experimental::is_detected` and related traits.
+// See https://en.cppreference.com/w/cpp/experimental/is_detected
+//
+// It's a utility for concisely writing traits. It allows a simple
+// `Op<...>` alias template to be interrogated for substitution
+// failure, and a few related utilities cover common uses of it.
+//
+// Examples:
+// template <typename T>
+// using HasAValueTypeOp = typename T::value_type;
+//
+// template <typename T>
+// constexpr bool hasAValueType = stdx::is_detected_v<HasAValueType, T>;
+//
+// // You can also access what the Op's type result was if it succeeds.
+// // If it fails, the typedef will be the sentinel `stdx::nonesuch` type.
+// template <typename T>
+// using InThatCaseWhatWasIt = stdx::is_detected_t<HasAValueType, T>;
+//
+// // Or provide your own default:
+// template <typename T>
+// using ValueTypeOrVoid = stdx::is_detected_or_t<void, HasAValueType, T>;
+//
+// This std::experimental TS2 API may or may not be present in
+// toolchain, so it's simplest to provide a full implementation
+// here until such time as it's available in `std::` or the trait
+// creation niche is filled by simpler language features (e.g.
+// `concept`) and we all migrate off of direct SFINAE.
+namespace mongo::stdx {
+namespace detail {
+template <typename Default, typename AlwaysVoid, template <class...> class Op, typename... Args>
+struct Detector {
+ using value_t = std::false_type;
+ using type = Default;
+};
+template <typename Default, template <class...> class Op, typename... Args>
+struct Detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
+ using value_t = std::true_type;
+ using type = Op<Args...>;
+};
+} // namespace detail
+
+struct nonesuch {
+ nonesuch() = delete;
+ ~nonesuch() = delete;
+ nonesuch(const nonesuch&) = delete;
+ nonesuch& operator=(const nonesuch&) = delete;
+};
+
+template <template <class...> class Op, typename... Args>
+using is_detected = typename detail::Detector<nonesuch, void, Op, Args...>::value_t;
+
+template <template <class...> class Op, typename... Args>
+using detected_t = typename detail::Detector<nonesuch, void, Op, Args...>::type;
+
+template <template <class...> class Op, typename... Args>
+constexpr bool is_detected_v = is_detected<Op, Args...>::value;
+
+template <typename Default, template <class...> class Op, typename... Args>
+using detected_or = detail::Detector<Default, void, Op, Args...>;
+
+template <typename Default, template <class...> class Op, typename... Args>
+using detected_or_t = typename detected_or<Default, Op, Args...>::type;
+
+template <typename Expected, template <class...> class Op, typename... Args>
+using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
+
+template <typename Expected, template <class...> class Op, typename... Args>
+constexpr bool is_detected_exact_v = is_detected_exact<Expected, Op, Args...>::value;
+
+template <typename To, template <class...> class Op, typename... Args>
+using is_detected_convertible = std::is_convertible<detected_t<Op, Args...>, To>;
+
+template <typename To, template <class...> class Op, typename... Args>
+constexpr bool is_detected_convertible_v = is_detected_convertible<To, Op, Args...>::value;
+
+} // namespace mongo::stdx