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
std::is_convertible<const Replaceable<T>&&, T>::value> {};
} // namespace replaceable_detail
// Type trait template to statically test whether a type is a specialization of
// Replaceable
template <class T>
struct is_replaceable : std::false_type {};
template <class T>
struct is_replaceable<Replaceable<T>> : std::true_type {};
using is_replaceable = detail::is_instantiation_of<Replaceable, T>;
// Function to make a Replaceable with a type deduced from its input
template <class T>
......
......@@ -149,6 +149,25 @@ using bool_constant = std::integral_constant<bool, B>;
template <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
*
......
......@@ -27,10 +27,8 @@
namespace folly {
namespace array_detail {
template <typename>
struct is_ref_wrapper : std::false_type {};
template <typename T>
struct is_ref_wrapper<std::reference_wrapper<T>> : std::true_type {};
template <class T>
using is_ref_wrapper = detail::is_instantiation_of<std::reference_wrapper, T>;
template <typename T>
using not_ref_wrapper =
......
......@@ -25,6 +25,7 @@
#include <folly/Executor.h>
#include <folly/Portability.h>
#include <folly/ScopeGuard.h>
#include <folly/Traits.h>
#include <folly/Try.h>
#include <folly/experimental/coro/CurrentExecutor.h>
#include <folly/experimental/coro/Traits.h>
......@@ -482,9 +483,7 @@ inline Task<void> detail::TaskPromise<void>::get_return_object() noexcept {
namespace detail {
template <typename T>
struct is_task : std::false_type {};
template <typename T>
struct is_task<Task<T>> : std::true_type {};
using is_task = folly::detail::is_instantiation_of<Task, T>;
template <typename F, typename... A, typename F_, typename... A_>
invoke_result_t<F, A...> co_invoke_(F_ f, A_... a) {
......
......@@ -27,11 +27,8 @@ namespace coro {
namespace detail {
template <typename T>
struct _is_coroutine_handle : std::false_type {};
template <typename T>
struct _is_coroutine_handle<std::experimental::coroutine_handle<T>>
: std::true_type {};
using _is_coroutine_handle =
folly::detail::is_instantiation_of<std::experimental::coroutine_handle, T>;
template <typename T>
struct _is_valid_await_suspend_return_type : folly::Disjunction<
......
......@@ -39,10 +39,8 @@ constexpr Pointer const& get_underlying(propagate_const<Pointer> const& obj) {
}
namespace detail {
template <typename>
struct is_propagate_const : std::false_type {};
template <typename Pointer>
struct is_propagate_const<propagate_const<Pointer>> : std::true_type {};
template <class Pointer>
using is_propagate_const = is_instantiation_of<propagate_const, Pointer>;
template <typename T>
using is_decay_propagate_const = is_propagate_const<std::decay_t<T>>;
......
......@@ -62,6 +62,10 @@ struct F3 : T3 {
};
struct F4 : T1 {};
template <class>
struct A {};
struct B {};
namespace folly {
template <>
struct IsRelocatable<T1> : std::true_type {};
......@@ -392,3 +396,8 @@ TEST(Traits, like) {
(std::is_same<like_t<int const volatile&&, char>, char const volatile&&>::
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