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