add folly::void_t like C++17's std::void_t
authorEric Niebler <eniebler@fb.com>
Sat, 7 Jan 2017 02:32:01 +0000 (18:32 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Sat, 7 Jan 2017 02:32:51 +0000 (18:32 -0800)
Summary:
C++17 is adding std::void_t. It's handy for controlling class template partial specialization. Folly should have it too.

See http://en.cppreference.com/w/cpp/types/void_t

Reviewed By: yfeldblum

Differential Revision: D4387302

fbshipit-source-id: 85f955f3d8cfacbd6c9e61fb3f5cf53c056459bb

folly/Traits.h
folly/test/TraitsTest.cpp

index 81f52d0a2cdde961fb6c8636c7a08c1a52e07557..88d46a581648a8207e764a8cb908a7ab9058d59a 100644 (file)
@@ -149,6 +149,41 @@ namespace folly {
 template <typename T>
 using _t = typename T::type;
 
+/**
+ *  void_t
+ *
+ *  A type alias for `void`. `void_t` is useful for controling class-template
+ *  partial specialization.
+ *
+ *  Example:
+ *
+ *    // has_value_type<T>::value is true if T has a nested type `value_type`
+ *    template <class T, class = void>
+ *    struct has_value_type
+ *        : std::false_type {};
+ *
+ *    template <class T>
+ *    struct has_value_type<T, folly::void_t<typename T::value_type>>
+ *        : std::true_type {};
+ */
+#if defined(__cpp_lib_void_t) || defined(_MSC_VER)
+
+/* using override */ using std::void_t;
+
+#else // defined(__cpp_lib_void_t) || defined(_MSC_VER)
+
+namespace traits_detail {
+template <class...>
+struct void_t_ {
+  using type = void;
+};
+} // namespace traits_detail
+
+template <class... Ts>
+using void_t = _t<traits_detail::void_t_<Ts...>>;
+
+#endif // defined(__cpp_lib_void_t) || defined(_MSC_VER)
+
 /**
  * IsRelocatable<T>::value describes the ability of moving around
  * memory a value of type T by using memcpy (as opposed to the
index d4926514a3e65d0a3c7d955ed6a43d7233cc560b..fa6b663749fc43e880baa06d31706364ca3bf1f2 100644 (file)
@@ -216,3 +216,23 @@ TEST(Traits, actuallyRelocatable) {
 
   testIsRelocatable<std::vector<char>>(5, 'g');
 }
+
+namespace {
+// has_value_type<T>::value is true if T has a nested type `value_type`
+template <class T, class = void>
+struct has_value_type : std::false_type {};
+
+template <class T>
+struct has_value_type<T, folly::void_t<typename T::value_type>>
+    : std::true_type {};
+}
+
+TEST(Traits, void_t) {
+  EXPECT_TRUE((::std::is_same<folly::void_t<>, void>::value));
+  EXPECT_TRUE((::std::is_same<folly::void_t<int>, void>::value));
+  EXPECT_TRUE((::std::is_same<folly::void_t<int, short>, void>::value));
+  EXPECT_TRUE(
+      (::std::is_same<folly::void_t<int, short, std::string>, void>::value));
+  EXPECT_TRUE((::has_value_type<std::string>::value));
+  EXPECT_FALSE((::has_value_type<int>::value));
+}