Commit 626871c3 authored by Joe Loser's avatar Joe Loser Committed by Facebook Github Bot

Check if type is instantiation of a template (#1184)

Summary:
- There is not an easy way to check if a given type is an instantiation
  of a class template.
- The common solution is to write a custom trait each time and
  specialize it for the given instantiation so that the trait returns
  `std:true_type`.
- Add `is_instantiation_of` to help with DRY in custom traits for
  checking if a type is an instance of a given class template. Note that
  this does not work when the class template has a mix of type and
  non-type template parameters. It only works with types.
Pull Request resolved: https://github.com/facebook/folly/pull/1184

Reviewed By: vitaut

Differential Revision: D16161679

Pulled By: yfeldblum

fbshipit-source-id: c933fd3db7c56f61b6784fdcd199ff7963d61d8f
parent 06a918b7
...@@ -372,13 +372,8 @@ struct is_convertible_from_replaceable ...@@ -372,13 +372,8 @@ struct is_convertible_from_replaceable
std::is_convertible<const Replaceable<T>&&, T>::value> {}; std::is_convertible<const Replaceable<T>&&, T>::value> {};
} // namespace replaceable_detail } // namespace replaceable_detail
// Type trait template to statically test whether a type is a specialization of
// Replaceable
template <class T> template <class T>
struct is_replaceable : std::false_type {}; using is_replaceable = detail::is_instantiation_of<Replaceable, T>;
template <class T>
struct is_replaceable<Replaceable<T>> : std::true_type {};
// Function to make a Replaceable with a type deduced from its input // Function to make a Replaceable with a type deduced from its input
template <class T> template <class T>
......
...@@ -149,6 +149,25 @@ using bool_constant = std::integral_constant<bool, B>; ...@@ -149,6 +149,25 @@ using bool_constant = std::integral_constant<bool, B>;
template <std::size_t I> template <std::size_t I>
using index_constant = std::integral_constant<std::size_t, I>; using index_constant = std::integral_constant<std::size_t, I>;
namespace detail {
/**
* A type trait to check if a given type is an instantiation of a class
* template.
*
* Note that this only works with template type parameters. It does not work
* with non-type template parameters, template template parameters, or alias
* templates.
*/
template <template <typename...> class, typename>
struct is_instantiation_of : std::false_type {};
template <template <typename...> class C, typename... T>
struct is_instantiation_of<C, C<T...>> : std::true_type {};
template <template <typename...> class C, typename T>
constexpr bool is_instantiation_of_v = is_instantiation_of<C, T>::value;
} // namespace detail
/*** /***
* _t * _t
* *
......
...@@ -27,10 +27,8 @@ ...@@ -27,10 +27,8 @@
namespace folly { namespace folly {
namespace array_detail { namespace array_detail {
template <typename> template <class T>
struct is_ref_wrapper : std::false_type {}; using is_ref_wrapper = detail::is_instantiation_of<std::reference_wrapper, T>;
template <typename T>
struct is_ref_wrapper<std::reference_wrapper<T>> : std::true_type {};
template <typename T> template <typename T>
using not_ref_wrapper = using not_ref_wrapper =
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <folly/Executor.h> #include <folly/Executor.h>
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/ScopeGuard.h> #include <folly/ScopeGuard.h>
#include <folly/Traits.h>
#include <folly/Try.h> #include <folly/Try.h>
#include <folly/experimental/coro/CurrentExecutor.h> #include <folly/experimental/coro/CurrentExecutor.h>
#include <folly/experimental/coro/Traits.h> #include <folly/experimental/coro/Traits.h>
...@@ -482,9 +483,7 @@ inline Task<void> detail::TaskPromise<void>::get_return_object() noexcept { ...@@ -482,9 +483,7 @@ inline Task<void> detail::TaskPromise<void>::get_return_object() noexcept {
namespace detail { namespace detail {
template <typename T> template <typename T>
struct is_task : std::false_type {}; using is_task = folly::detail::is_instantiation_of<Task, T>;
template <typename T>
struct is_task<Task<T>> : std::true_type {};
template <typename F, typename... A, typename F_, typename... A_> template <typename F, typename... A, typename F_, typename... A_>
invoke_result_t<F, A...> co_invoke_(F_ f, A_... a) { invoke_result_t<F, A...> co_invoke_(F_ f, A_... a) {
......
...@@ -27,11 +27,8 @@ namespace coro { ...@@ -27,11 +27,8 @@ namespace coro {
namespace detail { namespace detail {
template <typename T> template <typename T>
struct _is_coroutine_handle : std::false_type {}; using _is_coroutine_handle =
folly::detail::is_instantiation_of<std::experimental::coroutine_handle, T>;
template <typename T>
struct _is_coroutine_handle<std::experimental::coroutine_handle<T>>
: std::true_type {};
template <typename T> template <typename T>
struct _is_valid_await_suspend_return_type : folly::Disjunction< struct _is_valid_await_suspend_return_type : folly::Disjunction<
......
...@@ -39,10 +39,8 @@ constexpr Pointer const& get_underlying(propagate_const<Pointer> const& obj) { ...@@ -39,10 +39,8 @@ constexpr Pointer const& get_underlying(propagate_const<Pointer> const& obj) {
} }
namespace detail { namespace detail {
template <typename> template <class Pointer>
struct is_propagate_const : std::false_type {}; using is_propagate_const = is_instantiation_of<propagate_const, Pointer>;
template <typename Pointer>
struct is_propagate_const<propagate_const<Pointer>> : std::true_type {};
template <typename T> template <typename T>
using is_decay_propagate_const = is_propagate_const<std::decay_t<T>>; using is_decay_propagate_const = is_propagate_const<std::decay_t<T>>;
......
...@@ -62,6 +62,10 @@ struct F3 : T3 { ...@@ -62,6 +62,10 @@ struct F3 : T3 {
}; };
struct F4 : T1 {}; struct F4 : T1 {};
template <class>
struct A {};
struct B {};
namespace folly { namespace folly {
template <> template <>
struct IsRelocatable<T1> : std::true_type {}; struct IsRelocatable<T1> : std::true_type {};
...@@ -392,3 +396,8 @@ TEST(Traits, like) { ...@@ -392,3 +396,8 @@ TEST(Traits, like) {
(std::is_same<like_t<int const volatile&&, char>, char const volatile&&>:: (std::is_same<like_t<int const volatile&&, char>, char const volatile&&>::
value)); value));
} }
TEST(Traits, is_instantiation_of) {
EXPECT_TRUE((detail::is_instantiation_of_v<A, A<int>>));
EXPECT_FALSE((detail::is_instantiation_of_v<A, B>));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment