sfinae_utility.hpp
Go to the documentation of this file.
1 
15 #ifndef MLPACK_CORE_SFINAE_UTILITY
16 #define MLPACK_CORE_SFINAE_UTILITY
17 
18 #include <type_traits>
19 #include <cstring>
20 
21 namespace mlpack {
22 namespace sfinae {
23 
24 /*
25  * MethodFormDetector is a tool that helps to find out whether a given class has
26  * a method of the requested form. For that purpose MethodFormDetector defines
27  * an operator() that accepts a class member pointer for the given class. If the
28  * operator()(&Class::Method) call can be compiled, then the given class has a
29  * method of the requested form. For any provided AdditionalArgsCount, the check
30  * succeeds only if the given class has exactly one method of the requested form
31  * with AdditionalArgsCount additional arguments.
32  *
33  * The tool is dedicated to be used in type functions (structs) generated by the
34  * macro HAS_METHOD_FORM.
35  *
36  * @tparam MethodForm A template class member pointer type to a method of the
37  * form to look for.
38  * @tparam Class A class in which a method of the requested form should be
39  * looked for.
40  * @tparam AdditionalArgsCount A number of additional arguments.
41  */
42 template<typename Class,
43  template<typename...> class MethodForm,
44  size_t AdditionalArgsCount>
46 
47 template<typename Class, template<typename...> class MethodForm>
48 struct MethodFormDetector<Class, MethodForm, 0>
49 {
50  void operator()(MethodForm<Class>);
51 };
52 
53 template<typename Class, template<typename...> class MethodForm>
54 struct MethodFormDetector<Class, MethodForm, 1>
55 {
56  template<class T1>
57  void operator()(MethodForm<Class, T1>);
58 };
59 
60 template<typename Class, template<typename...> class MethodForm>
61 struct MethodFormDetector<Class, MethodForm, 2>
62 {
63  template<class T1, class T2>
64  void operator()(MethodForm<Class, T1, T2>);
65 };
66 
67 template<typename Class, template<typename...> class MethodForm>
68 struct MethodFormDetector<Class, MethodForm, 3>
69 {
70  template<class T1, class T2, class T3>
71  void operator()(MethodForm<Class, T1, T2, T3>);
72 };
73 
74 template<typename Class, template<typename...> class MethodForm>
75 struct MethodFormDetector<Class, MethodForm, 4>
76 {
77  template<class T1, class T2, class T3, class T4>
78  void operator()(MethodForm<Class, T1, T2, T3, T4>);
79 };
80 
81 template<typename Class, template<typename...> class MethodForm>
82 struct MethodFormDetector<Class, MethodForm, 5>
83 {
84  template<class T1, class T2, class T3, class T4, class T5>
85  void operator()(MethodForm<Class, T1, T2, T3, T4, T5>);
86 };
87 
88 template<typename Class, template<typename...> class MethodForm>
89 struct MethodFormDetector<Class, MethodForm, 6>
90 {
91  template<class T1, class T2, class T3, class T4, class T5, class T6>
92  void operator()(MethodForm<Class, T1, T2, T3, T4, T5, T6>);
93 };
94 
95 template<typename Class, template<typename...> class MethodForm>
96 struct MethodFormDetector<Class, MethodForm, 7>
97 {
98  template<class T1, class T2, class T3, class T4, class T5, class T6, class T7>
99  void operator()(MethodForm<Class, T1, T2, T3, T4, T5, T6, T7>);
100 };
101 
102 } // namespace sfinae
103 } // namespace mlpack
104 
106 template<typename U, U> struct SigCheck : std::true_type {};
107 
108 /*
109  * Constructs a template supporting the SFINAE pattern.
110  *
111  * This macro generates a template struct that is useful for enabling/disabling
112  * a method if the template class passed in contains a member function matching
113  * a given signature with a specified name.
114  *
115  * The generated struct should be used in conjunction with std::enable_if_t.
116  *
117  * For general references, see:
118  * http://stackoverflow.com/a/264088/391618
119  *
120  * For an mlpack specific use case, see /mlpack/core/util/prefixedoutstream.hpp
121  * and /mlpack/core/util/prefixedoutstream_impl.hpp
122  *
123  * @param NAME the name of the struct to construct. For example: HasToString
124  * @param FUNC the name of the function to check for. For example: ToString
125  */
126 #define HAS_MEM_FUNC(FUNC, NAME) \
127 
template
<
typename
T
,
typename
sig
,
typename
=
std::true_type
>
128 struct NAME : std::false_type {}; \
129  \
130 
template
<
typename
T
,
typename
sig
>
131 struct NAME \
132 < \
133  T, \
134  sig, \
135  std::integral_constant<bool, SigCheck<sig, &T::FUNC>::value> \
136 > : std::true_type {};
137 
141 #define HAS_METHOD_FORM_BASE(METHOD, NAME, MAXN) \
142 template<typename Class, \
143  template<typename...> class MF /* MethodForm */, \
144  size_t MinN = 0 /* MinNumberOfAdditionalArgs */> \
145 struct NAME \
146 { \
147  /* Making a short alias for MethodFormDetector */ \
148  template<typename C, template<typename...> class MethodForm, int N> \
149  using MFD = mlpack::sfinae::MethodFormDetector<C, MethodForm, N>; \
150  \
151  template<size_t N> \
152  struct WithNAdditionalArgs \
153  { \
154  using yes = char[1]; \
155  using no = char[2]; \
156  \
157 
template
<
typename
T
,
typename
ResultType
>
158  using EnableIfVoid = \
159  typename std::enable_if<std::is_void<T>::value, ResultType>::type; \
160  \
161 
template
<
typename
C
>
162  static EnableIfVoid<decltype(MFD<C, MF, N>()(&C::METHOD)), yes&> chk(int); \
163 
template
<
typename
>
164  static no& chk(...); \
165  \
166  static const bool value = sizeof(chk<Class>(0)) == sizeof(yes); \
167  }; \
168  \
169  template<size_t N> \
170  struct WithGreaterOrEqualNumberOfAdditionalArgs \
171  { \
172  using type = typename std::conditional< \
173  WithNAdditionalArgs<N>::value, \
174  std::true_type, \
175  typename std::conditional< \
176  N < MAXN, \
177  WithGreaterOrEqualNumberOfAdditionalArgs<N + 1>, \
178  std::false_type>::type>::type; \
179  static const bool value = type::value; \
180  }; \
181  \
182  static const bool value = \
183  WithGreaterOrEqualNumberOfAdditionalArgs<MinN>::value; \
184 };
185 
199 #define HAS_ANY_METHOD_FORM(FUNC, NAME) \
200 
template
<
typename
T
>
201 struct NAME \
202 { \
203 
template
<
typename
Q
=
T
>
204  static typename \
205  std::enable_if<std::is_member_function_pointer<decltype(&Q::FUNC)>::value, \
206  int>::type \
207  f(int) { return 1;} \
208  \
209 
template
<
typename
Q
=
T
>
210  static char f(char) { return 0; } \
211  \
212  static const bool value = sizeof(f<T>(0)) != sizeof(char); \
213 };
214 /*
215  * A macro that can be used for passing arguments containing commas to other
216  * macros.
217  */
218 #define SINGLE_ARG(...) __VA_ARGS__
219 
251 #define HAS_METHOD_FORM(METHOD, NAME) \
252  HAS_METHOD_FORM_BASE(SINGLE_ARG(METHOD), SINGLE_ARG(NAME), 7)
253 
285 #define HAS_EXACT_METHOD_FORM(METHOD, NAME) \
286  HAS_METHOD_FORM_BASE(SINGLE_ARG(METHOD), SINGLE_ARG(NAME), 0)
287 
321 #endif
.hpp
Definition: add_to_po.hpp:21
Utility struct for checking signatures.