Imported Upstream version 2.99.2
[platform/upstream/libsigc++.git] / sigc++ / functors / functor_trait.h
1 #ifndef _SIGC_FUNCTORS_FUNCTOR_TRAIT_H_
2 #define _SIGC_FUNCTORS_FUNCTOR_TRAIT_H_
3 #include <sigc++/functors/functor_base.h>
4 #include <sigc++/functors/mem_fun.h>
5 #include <sigc++/functors/ptr_fun.h>
6 #include <sigc++/type_traits.h>
7 #include <type_traits>
8
9 namespace sigc {
10
11 /** @defgroup sigcfunctors Functors
12  * Functors are copyable types that define operator()().
13  *
14  * Types that define operator()() overloads with different return types are referred to
15  * as multi-type functors. Multi-type functors are only partially supported in libsigc++.
16  *
17  * Closures are functors that store all information needed to invoke a callback from operator()().
18  *
19  * Adaptors are functors that alter the signature of a functor's operator()().
20  *
21  * libsigc++ defines numerous functors, closures and adaptors.
22  * Since libsigc++ is a callback library, most functors are also closures.
23  * The documentation doesn't distinguish between functors and closures.
24  *
25  * The basic functor types libsigc++ provides are created with ptr_fun() and mem_fun()
26  * and can be converted into slots implicitly.
27  * The set of adaptors that ships with libsigc++ is documented in the @ref adaptors module.
28  *
29  * If you want to mix user-defined and third party functors with libsigc++,
30  * and you want them to be implicitly convertible into slots, libsigc++ must know
31  * the result type of your functors. There are different ways to achieve that.
32  *
33  * - Derive your functors from sigc::functor_base and place
34  *   <tt>using result_type = T_return;</tt> in the class definition.
35  * - Use the macro SIGC_FUNCTOR_TRAIT(T_functor,T_return) in namespace sigc.
36  *   Multi-type functors are only partly supported.
37  * - For functors not derived from sigc::functor_base, and not specified with
38  *   SIGC_FUNCTOR_TRAIT(), libsigc++ tries to deduce the result type with the
39  *   C++11 decltype() specifier. That attempt usually succeeds if the functor
40  *   has a single operator()(), but it fails if operator()() is overloaded.
41  * - Use the macro #SIGC_FUNCTORS_HAVE_RESULT_TYPE, if you want libsigc++ to assume
42  *   that result_type is defined in all user-defined or third party functors,
43  *   whose result type can't be deduced in any other way.
44  *
45  * If all these ways to deduce the result type fail, void is assumed.
46  *
47  * With libsigc++ versions before 2.6, the macro 
48  * #SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE activated the test with
49  * decltype(). That macro is now unneccesary and deprecated.
50  */
51
52 /** Helper class, to determine if decltype() can deduce the result type of a functor.
53  *
54  * @ingroup sigcfunctors
55  */
56 template <typename T_functor>
57 class can_deduce_result_type_with_decltype
58 {
59 private:
60   struct biggerthanint
61   {
62     int memory1;
63     int memory2;
64     int memory3;
65     int memory4;
66   };
67
68   static biggerthanint checksize(...);
69
70   // If decltype(&X_functor::operator()) can't be evaluated, this checksize() overload
71   // is ignored because of the SFINAE rule (Substitution Failure Is Not An Error).
72   template <typename X_functor>
73   static int checksize(X_functor* obj, decltype(&X_functor::operator()) p = nullptr);
74
75 public:
76   static const bool value
77 #ifndef DOXYGEN_SHOULD_SKIP_THIS
78     = sizeof(checksize(static_cast<T_functor*>(nullptr))) == sizeof(int)
79 #endif
80     ;
81 };
82
83
84 /** Trait that specifies the return type of any type.
85  * Template specializations for functors derived from sigc::functor_base,
86  * for other functors whose result type can be deduced with decltype(),
87  * for function pointers and for class methods are provided.
88  *
89  * @tparam T_functor Functor type.
90  * @tparam I_derives_functor_base Whether @p T_functor inherits from sigc::functor_base.
91  * @tparam I_can_use_decltype Whether the result type of @p T_functor can be deduced
92  *                            with decltype().
93  *
94  * @ingroup sigcfunctors
95  */
96 template <class T_functor,
97           bool I_derives_functor_base = std::is_base_of<functor_base,T_functor>::value,
98           bool I_can_use_decltype = can_deduce_result_type_with_decltype<T_functor>::value>
99 struct functor_trait
100 {
101   using result_type = void;
102   using functor_type = T_functor;
103 };
104
105 #ifndef DOXYGEN_SHOULD_SKIP_THIS
106 template <class T_functor, bool I_can_use_decltype>
107 struct functor_trait<T_functor, true, I_can_use_decltype>
108 {
109   using result_type = typename T_functor::result_type;
110   using functor_type = T_functor;
111 };
112
113 template <typename T_functor>
114 struct functor_trait<T_functor, false, true>
115 {
116   using result_type = typename functor_trait<decltype(&T_functor::operator()), false, false>::result_type;
117   using functor_type = T_functor;
118 };
119 #endif // DOXYGEN_SHOULD_SKIP_THIS
120
121 /** Helper macro, if you want to mix user-defined and third party functors with libsigc++.
122  *
123  * If you want to mix functors not derived from sigc::functor_base with libsigc++, and
124  * these functors define @p result_type, use this macro inside namespace sigc like so:
125  * @code
126  * namespace sigc { SIGC_FUNCTORS_HAVE_RESULT_TYPE }
127  * @endcode
128  *
129  * @ingroup sigcfunctors
130  */
131 #define SIGC_FUNCTORS_HAVE_RESULT_TYPE                 \
132 template <class T_functor>                             \
133 struct functor_trait<T_functor, false, false>          \
134 {                                                      \
135   using result_type = typename T_functor::result_type; \
136   using functor_type = T_functor;                      \
137 };
138
139 /** Helper macro, if you want to mix user-defined and third party functors with libsigc++.
140  *
141  * If you want to mix functors not derived from sigc::functor_base with libsigc++, and
142  * these functors don't define @p result_type, use this macro inside namespace sigc
143  * to expose the return type of the functors like so:
144  * @code
145  * namespace sigc {
146  *   SIGC_FUNCTOR_TRAIT(first_functor_type, return_type_of_first_functor_type)
147  *   SIGC_FUNCTOR_TRAIT(second_functor_type, return_type_of_second_functor_type)
148  *   ...
149  * }
150  * @endcode
151  *
152  * @ingroup sigcfunctors
153  */
154 #define SIGC_FUNCTOR_TRAIT(T_functor,T_return) \
155 template <>                                    \
156 struct functor_trait<T_functor, false, false>  \
157 {                                              \
158   using result_type = T_return;                \
159   using functor_type = T_functor;              \
160 };                                             \
161 template <>                                    \
162 struct functor_trait<T_functor, false, true>   \
163 {                                              \
164   using result_type = T_return;                \
165   using functor_type = T_functor;              \
166 };
167
168 #ifndef SIGCXX_DISABLE_DEPRECATED
169 /** Helper macro, if you want to mix user-defined and third party functors with libsigc++.
170  *
171  * If you want to mix functors not derived from sigc::functor_base with libsigc++,
172  * and your compiler can deduce the result type of the functor with the C++11
173  * keyword <tt>decltype</tt>, use this macro inside namespace sigc like so:
174  * @code
175  * namespace sigc {
176  *   SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
177  * }
178  * @endcode
179  *
180  * Functors with overloaded operator()() are not supported.
181  *
182  * @newin{2,2,11}
183  *
184  * @deprecated This macro does nothing. The test it activated in libsigc++
185  *             versions before 2.6, is now unconditionally activated.
186  *
187  * @ingroup sigcfunctors
188  */
189 #define SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE // Empty
190 #endif // SIGCXX_DISABLE_DEPRECATED
191
192 #ifndef DOXYGEN_SHOULD_SKIP_THIS
193 // detect the return type and the functor version of non-functor types.
194
195 //functor ptr fun:
196
197 template <class T_return, class... T_arg>
198 struct functor_trait<T_return (*)(T_arg...), false, false>
199 {
200   using result_type = T_return;
201   using functor_type = pointer_functor<T_return(T_arg...)>;
202 };
203
204
205 //functor mem fun:
206
207 template <class T_return, class T_obj, class... T_arg>
208 struct functor_trait<T_return (T_obj::*)(T_arg...), false, false>
209 {
210   using result_type = T_return;
211   using functor_type = mem_functor<
212     T_return (T_obj::*)(T_arg...),
213     T_arg...>;
214 };
215
216 template <class T_return, class T_obj, class... T_arg>
217 struct functor_trait<T_return (T_obj::*)(T_arg...) const, false, false>
218 {
219   using result_type = T_return;
220   using functor_type = mem_functor<
221     T_return (T_obj::*)(T_arg...) const,
222     T_arg...>;
223 };
224
225 #endif // DOXYGEN_SHOULD_SKIP_THIS
226
227 } /* namespace sigc */
228 #endif /* _SIGC_FUNCTORS_FUNCTOR_TRAIT_H_ */