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  using args = meta::list<>;
42  static constexpr FunctionKind kind = FunctionKind::INVALID;
43  };
44 
45  template<typename R, typename... Args>
46  struct get_function_signature<R(Args...)>
47  {
48  using args = meta::list<Args...>;
49  using args_without_this = args;
50  using return_type = R;
51 
52  static constexpr FunctionKind kind = FunctionKind::FREE_FUNCTION;
53  };
54 
55  template<typename R, typename... Args>
56  struct get_function_signature<R(*)(Args...)> :
57  public get_function_signature<R(Args...)>
58  {};
59 
60  template<typename C, typename R, typename... Args>
61  struct get_function_signature<R (C::*)(Args...)>
62  {
63  using args = meta::list<C, Args...>;
64  using args_without_this = meta::list<Args...>;
65  using return_type = R;
66  static constexpr FunctionKind kind = FunctionKind::MEMBER_FUNCTION;
67  };
68 
69  template<typename C, typename R, typename... Args>
70  struct get_function_signature<R (C::*)(Args...) const>
71  {
72  using args = meta::list<C, Args...>;
73  using args_without_this = meta::list<Args...>;
74  using return_type = R;
75  static constexpr FunctionKind kind = FunctionKind::CONST_MEMBER_FUNCTION;
76  };
77 
78  /*
79  * Ok, pointers to data members are not functions but callables (See cpp::callable())
80  * Maybe we should change this whole header and call it callable_traits
81  */
82  template<typename T, typename Class>
83  struct get_function_signature<T Class::*>
84  {
85  using args = meta::list<Class>;
86  using args_without_this = meta::list<>;
87  using return_type = T;
88  static constexpr FunctionKind kind = FunctionKind::MEMBER_OBJECT;
89  };
90 }
91 
92 template<typename Function, bool IsFunctor = detail::IsFunctorClass<Function>::value>
93 struct function_signature : public
94  detail::get_function_signature<Function>
95 {};
96 
97 template<typename Functor>
98 struct function_signature<Functor, true>
99 {
100  // Function pointers include the class type as first argument,
101  // remove it since functors are callable themselves without any
102  // extra object
103  using args = meta::tail_t<
104  typename detail::get_function_signature<decltype(&Functor::operator())>::args
105  >;
106  using args_without_this = args;
107  using return_type = typename detail::get_function_signature<decltype(&Functor::operator())>::return_type;
108 
109  static constexpr FunctionKind kind = FunctionKind::FUNCTOR;
110 };
111 
112 template<typename Function>
113 using function_return_type = typename function_signature<Function>::return_type;
114 
115 template<typename Function>
116 using function_arguments = typename function_signature<Function>::args;
117 
118 template<typename Function>
119 using function_arguments_without_this = typename function_signature<Function>::args_without_this;
120 
121 template<std::size_t Index, typename Function>
122 using function_argument = meta::get_t<Index, function_arguments<Function>>;
123 
124 template<typename Function>
125 constexpr FunctionKind function_kind()
126 {
127  return function_signature<Function>::kind;
128 }
129 
130 template<typename Function>
131 constexpr FunctionKind function_kind(Function)
132 {
133  return function_kind<Function>();
134 }
135 
136 template<typename A, typename B>
137 struct equal_signature : std::is_same<
138  function_arguments_without_this<A>, function_arguments_without_this<B>
139 >{};
140 
141 }
142 
143 #endif // SIPLASPLAS_UTILITY_FUNCTION_TRAITS_HPP
Definition: canary_allocator.hpp:7