type_t, a generalization of void_t
authorYedidya Feldblum <yfeldblum@fb.com>
Fri, 27 Oct 2017 02:35:23 +0000 (19:35 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Fri, 27 Oct 2017 02:55:40 +0000 (19:55 -0700)
Summary: [Folly] `type_t`, a generalization of `void_t`.

Reviewed By: ericniebler

Differential Revision: D6082913

fbshipit-source-id: f9557b5da1f6684b12d570b6c1bd52c102cb0703

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

index d1ab157a4d4e2494a6eb0349356b86c73a390d8e..ebf69acf7e30628fe0f5d7b88811ad5966833e8d 100644 (file)
@@ -156,10 +156,26 @@ template <typename T>
 using _t = typename T::type;
 
 /**
+ *  type_t
+ *
+ *  A type alias for the first template type argument. `type_t` is useful for
+ *  controlling class-template and function-template partial specialization.
+ *
+ *  Example:
+ *
+ *    template <typename Value>
+ *    class Container {
+ *     public:
+ *      template <typename... Args>
+ *      Container(
+ *          type_t<in_place_t, decltype(Value(std::declval<Args>()...))>,
+ *          Args&&...);
+ *    };
+ *
  *  void_t
  *
  *  A type alias for `void`. `void_t` is useful for controling class-template
- *  partial specialization.
+ *  and function-template partial specialization.
  *
  *  Example:
  *
@@ -205,13 +221,16 @@ using _t = typename T::type;
 
 namespace traits_detail {
 template <class...>
-struct void_t_ {
-  using type = void;
+struct type_t_ {
+  template <class T>
+  using apply = T;
 };
 } // namespace traits_detail
 
+template <class T, class... Ts>
+using type_t = typename traits_detail::type_t_<Ts...>::template apply<T>;
 template <class... Ts>
-using void_t = _t<traits_detail::void_t_<Ts...>>;
+using void_t = type_t<void, Ts...>;
 
 /**
  * IsRelocatable<T>::value describes the ability of moving around
index b0214d4624b1d4239d979f62c7f357fa4d752d91..bfb3f7a73dcd3c634c1516d595c93a5b68607c33 100644 (file)
@@ -229,6 +229,16 @@ 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 {};
+
+struct some_tag {};
+
+template <typename T>
+struct container {
+  template <class... Args>
+  container(
+      folly::type_t<some_tag, decltype(T(std::declval<Args>()...))>,
+      Args&&...) {}
+};
 } // namespace
 
 TEST(Traits, void_t) {
@@ -240,3 +250,18 @@ TEST(Traits, void_t) {
   EXPECT_TRUE((::has_value_type<std::string>::value));
   EXPECT_FALSE((::has_value_type<int>::value));
 }
+
+TEST(Traits, type_t) {
+  EXPECT_TRUE((::std::is_same<folly::type_t<float>, float>::value));
+  EXPECT_TRUE((::std::is_same<folly::type_t<float, int>, float>::value));
+  EXPECT_TRUE((::std::is_same<folly::type_t<float, int, short>, float>::value));
+  EXPECT_TRUE(
+      (::std::is_same<folly::type_t<float, int, short, std::string>, float>::
+           value));
+  EXPECT_TRUE((
+      ::std::is_constructible<::container<std::string>, some_tag, std::string>::
+          value));
+  EXPECT_FALSE(
+      (::std::is_constructible<::container<std::string>, some_tag, float>::
+           value));
+}