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 
103 template<typename U, U> struct SigCheck : std::true_type {};
104 
105 } // namespace sfinae
106 } // namespace mlpack
107 
108 
109 
110 /*
111  * Constructs a template supporting the SFINAE pattern.
112  *
113  * This macro generates a template struct that is useful for enabling/disabling
114  * a method if the template class passed in contains a member function matching
115  * a given signature with a specified name.
116  *
117  * The generated struct should be used in conjunction with std::enable_if_t.
118  *
119  * For general references, see:
120  * http://stackoverflow.com/a/264088/391618
121  *
122  * For an mlpack specific use case, see /mlpack/core/util/prefixedoutstream.hpp
123  * and /mlpack/core/util/prefixedoutstream_impl.hpp
124  *
125  * @param NAME the name of the struct to construct. For example: HasToString
126  * @param FUNC the name of the function to check for. For example: ToString
127  */
128 #define HAS_MEM_FUNC(FUNC, NAME) \
129 
template
<
typename
T
,
typename
sig
,
typename
=
std::true_type
>
130 struct NAME : std::false_type {}; \
131  \
132 
template
<
typename
T
,
typename
sig
>
133 struct NAME \
134 < \
135  T, \
136  sig, \
137  std::integral_constant<bool, mlpack::sfinae::SigCheck<sig, &T::FUNC>::value> \
138 > : std::true_type {};
139 
143 #define HAS_METHOD_FORM_BASE(METHOD, NAME, MAXN) \
144 template<typename Class, \
145  template<typename...> class MF /* MethodForm */, \
146  size_t MinN = 0 /* MinNumberOfAdditionalArgs */> \
147 struct NAME \
148 { \
149  /* Making a short alias for MethodFormDetector */ \
150  template<typename C, template<typename...> class MethodForm, int N> \
151  using MFD = mlpack::sfinae::MethodFormDetector<C, MethodForm, N>; \
152  \
153  template<size_t N> \
154  struct WithNAdditionalArgs \
155  { \
156  using yes = char[1]; \
157  using no = char[2]; \
158  \
159 
template
<
typename
T
,
typename
ResultType
>
160  using EnableIfVoid = \
161  typename std::enable_if<std::is_void<T>::value, ResultType>::type; \
162  \
163 
template
<
typename
C
>
164  static EnableIfVoid<decltype(MFD<C, MF, N>()(&C::METHOD)), yes&> chk(int); \
165 
template
<
typename
>
166  static no& chk(...); \
167  \
168  static const bool value = sizeof(chk<Class>(0)) == sizeof(yes); \
169  }; \
170  \
171  template<size_t N> \
172  struct WithGreaterOrEqualNumberOfAdditionalArgs \
173  { \
174  using type = typename std::conditional< \
175  WithNAdditionalArgs<N>::value, \
176  std::true_type, \
177  typename std::conditional< \
178  N < MAXN, \
179  WithGreaterOrEqualNumberOfAdditionalArgs<N + 1>, \
180  std::false_type>::type>::type; \
181  static const bool value = type::value; \
182  }; \
183  \
184  static const bool value = \
185  WithGreaterOrEqualNumberOfAdditionalArgs<MinN>::value; \
186 };
187 
201 #define HAS_ANY_METHOD_FORM(FUNC, NAME) \
202 
template
<
typename
T
>
203 struct NAME \
204 { \
205 
template
<
typename
Q
=
T
>
206  static typename \
207  std::enable_if<std::is_member_function_pointer<decltype(&Q::FUNC)>::value, \
208  int>::type \
209  f(int) { return 1;} \
210  \
211 
template
<
typename
Q
=
T
>
212  static char f(char) { return 0; } \
213  \
214  static const bool value = sizeof(f<T>(0)) != sizeof(char); \
215 };
216 /*
217  * A macro that can be used for passing arguments containing commas to other
218  * macros.
219  */
220 #define SINGLE_ARG(...) __VA_ARGS__
221 
252 #define HAS_METHOD_FORM(METHOD, NAME) \
253  HAS_METHOD_FORM_BASE(SINGLE_ARG(METHOD), SINGLE_ARG(NAME), 7)
254 
285 #define HAS_EXACT_METHOD_FORM(METHOD, NAME) \
286  HAS_METHOD_FORM_BASE(SINGLE_ARG(METHOD), SINGLE_ARG(NAME), 0)
287 
321 #endif
Linear algebra utility functions, generally performed on matrices or vectors.
Utility struct for checking signatures.