CreateIsCallable.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <type_traits>
7 
8 #include "Utilities/TypeTraits.hpp"
9 
10 /*!
11  * \ingroup TypeTraitsGroup
12  * \brief Generate a type trait to check if a class has a member function that
13  * can be invoked with arguments of type `TArgs...`
14  *
15  * The usage of the type trait is identical to the usage of the
16  * `tt::is_callable` type trait. The name of the type trait is
17  * `is_METHOD_NAME_callable` and is not placed in
18  * the `tt` namespace. To avoid collisions it is highly recommended that type
19  * traits generated with this macro are generated into `_detail` namespaces.
20  * This will reduce redefinition compilation errors.
21  *
22  * Note that variable templates with `_r` and `_t` suffixes that follow the
23  * standard library's naming convention are also generated. To generate
24  * corresponding `_v` metafunctions, call `CREATE_IS_CALLABLE` first and then
25  * `CREATE_IS_CALLABLE_V` and/or `CREATE_IS_CALLABLE_R_V`.
26  *
27  * \example
28  * \snippet Test_CreateIsCallable.cpp CREATE_IS_CALLABLE_EXAMPLE
29  *
30  * \see tt::is_callable
31  */
32 #define CREATE_IS_CALLABLE(METHOD_NAME) \
33  struct AnyReturnType##METHOD_NAME {}; \
34  \
35  template <typename ReturnType, typename TT, typename... TArgs> \
36  class is_##METHOD_NAME##_callable_r { \
37  private: \
38  struct NotCallable {}; \
39  template <typename T, typename... Args> \
40  static auto test_callable(int) noexcept \
41  -> decltype(std::declval<T>().METHOD_NAME(std::declval<Args>()...)); \
42  template <typename, typename...> \
43  static auto test_callable(...) noexcept -> NotCallable; \
44  \
45  public: \
46  static constexpr bool value = \
47  (cpp17::is_same_v<ReturnType, AnyReturnType##METHOD_NAME> and \
48  not cpp17::is_same_v<decltype(test_callable<TT, TArgs...>(0)), \
49  NotCallable>) or \
50  cpp17::is_same_v<decltype(test_callable<TT, TArgs...>(0)), \
51  ReturnType>; \
52  using type = std::integral_constant<bool, value>; \
53  }; \
54  template <typename ReturnType, typename T, typename... Args> \
55  using is_##METHOD_NAME##_callable_r_t = \
56  typename is_##METHOD_NAME##_callable_r<ReturnType, T, Args...>::type; \
57  template <typename TT, typename... TArgs> \
58  using is_##METHOD_NAME##_callable = \
59  is_##METHOD_NAME##_callable_r<AnyReturnType##METHOD_NAME, TT, TArgs...>; \
60  template <typename TT, typename... TArgs> \
61  using is_##METHOD_NAME##_callable_t = \
62  is_##METHOD_NAME##_callable_r_t<AnyReturnType##METHOD_NAME, TT, \
63  TArgs...>;
64 
65 // Separate macros to avoid compiler warnings about unused variables
66 #define CREATE_IS_CALLABLE_R_V(METHOD_NAME) \
67  template <typename ReturnType, typename T, typename... Args> \
68  static constexpr const bool is_##METHOD_NAME##_callable_r_v = \
69  is_##METHOD_NAME##_callable_r<ReturnType, T, Args...>::value;
70 #define CREATE_IS_CALLABLE_V(METHOD_NAME) \
71  template <typename T, typename... Args> \
72  static constexpr const bool is_##METHOD_NAME##_callable_v = \
73  is_##METHOD_NAME##_callable<T, Args...>::value;
74 // @}