siplasplas
A library for C++ reflection and introspection
function_traits.hpp
1 #ifndef SIPLASPLAS_UTILITY_FUNCTION_TRAITS_HPP
2 #define SIPLASPLAS_UTILITY_FUNCTION_TRAITS_HPP
3 
4 #include "meta.hpp"
5 #include <type_traits>
6 #include <ctti/type_id.hpp>
7 
8 namespace cpp
9 {
10 
11 enum class FunctionKind
12 {
13  INVALID,
14  FREE_FUNCTION,
15  MEMBER_FUNCTION,
16  MEMBER_OBJECT,
17  CONST_MEMBER_FUNCTION,
18  FUNCTOR
19 };
20 
21 namespace detail
22 {
23  /*
24  * With VS2015 we still cannot use expression sfinae to check for operator(),
25  * so here we define a trait in the old way
26  */
27  template<typename T>
28  struct IsFunctorClass
29  {
30  template<typename U>
31  static std::true_type check(decltype(&U::operator(), nullptr));
32  template<typename U>
33  static std::false_type check(...);
34 
35  static constexpr bool value = decltype(check<T>(nullptr))::value;
36  };
37 
38  template<typename Function>
39  struct get_function_signature
40  {
41  static constexpr FunctionKind kind = FunctionKind::INVALID;
42  };
43 
44  template<typename R, typename... Args>
45  struct get_function_signature<R(Args...)>
46  {
47  using args = meta::list<Args...>;
48  using args_without_this = args;
49  using return_type = R;
50 
51  static constexpr FunctionKind kind = FunctionKind::FREE_FUNCTION;
52  };
53 
54  template<typename R, typename... Args>
55  struct get_function_signature<R(*)(Args...)> :
56  public get_function_signature<R(Args...)>
57  {};
58 
59  template<typename C, typename R, typename... Args>
60  struct get_function_signature<R (C::*)(Args...)>
61  {
62  using args = meta::list<C, Args...>;
63  using args_without_this = meta::list<Args...>;
64  using return_type = R;
65  static constexpr FunctionKind kind = FunctionKind::MEMBER_FUNCTION;
66  };
67 
68  template<typename C, typename R, typename... Args>
69  struct get_function_signature<R (C::*)(Args...) const>
70  {
71  using args = meta::list<C, Args...>;
72  using args_without_this = meta::list<Args...>;
73  using return_type = R;
74  static constexpr FunctionKind kind = FunctionKind::CONST_MEMBER_FUNCTION;
75  };
76 
77  /*
78  * Ok, pointers to data members are not functions but callables (See cpp::callable())
79  * Maybe we should change this whole header and call it callable_traits
80  */
81  template<typename T, typename Class>
82  struct get_function_signature<T Class::*>
83  {
84  using args = meta::list<Class>;
85  using args_without_this = meta::list<>;
86  using return_type = T;
87  static constexpr FunctionKind kind = FunctionKind::MEMBER_OBJECT;
88  };
89 }
90 
91 template<typename Function, bool IsFunctor = detail::IsFunctorClass<Function>::value>
92 struct function_signature : public
93  detail::get_function_signature<Function>
94 {};
95 
96 template<typename Functor>
97 struct function_signature<Functor, true>
98 {
99  // Function pointers include the class type as first argument,
100  // remove it since functors are callable themselves without any
101  // extra object
102  using args = meta::tail_t<
103  typename detail::get_function_signature<decltype(&Functor::operator())>::args
104  >;
105  using args_without_this = args;
106  using return_type = typename detail::get_function_signature<decltype(&Functor::operator())>::return_type;
107 
108  static constexpr FunctionKind kind = FunctionKind::FUNCTOR;
109 };
110 
111 template<typename Function>
112 using function_return_type = typename function_signature<Function>::return_type;
113 
114 template<typename Function>
115 using function_arguments = typename function_signature<Function>::args;
116 
117 template<typename Function>
118 using function_arguments_without_this = typename function_signature<Function>::args_without_this;
119 
120 template<std::size_t Index, typename Function>
121 using function_argument = meta::get_t<Index, function_arguments<Function>>;
122 
123 template<typename Function>
124 constexpr FunctionKind function_kind()
125 {
126  return function_signature<Function>::kind;
127 }
128 
129 template<typename Function>
130 constexpr FunctionKind function_kind(Function)
131 {
132  return function_kind<Function>();
133 }
134 
135 template<typename A, typename B>
136 struct equal_signature : std::is_same<
137  function_arguments_without_this<A>, function_arguments_without_this<B>
138 >{};
139 
140 }
141 
142 #endif // SIPLASPLAS_UTILITY_FUNCTION_TRAITS_HPP
Definition: canary_allocator.hpp:7