From: Eric Niebler <eniebler@fb.com>
Date: Sat, 7 Jan 2017 02:32:01 +0000 (-0800)
Subject: add folly::void_t like C++17's std::void_t
X-Git-Tag: v2017.03.06.00~124
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=e39748150f912c52987d65a6636f75506c873e35;p=folly.git

add folly::void_t like C++17's std::void_t

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
---

diff --git a/folly/Traits.h b/folly/Traits.h
index 81f52d0a..88d46a58 100644
--- a/folly/Traits.h
+++ b/folly/Traits.h
@@ -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
diff --git a/folly/test/TraitsTest.cpp b/folly/test/TraitsTest.cpp
index d4926514..fa6b6637 100644
--- a/folly/test/TraitsTest.cpp
+++ b/folly/test/TraitsTest.cpp
@@ -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));
+}