cheshirekow  v0.1.0
is_call_possible.h
Go to the documentation of this file.
1 /*
2  * is_call_possible.h
3  *
4  * Created on: Jul 14, 2014
5  * Author: josh
6  */
7 
8 #ifndef IS_CALL_POSSIBLE_H_
9 #define IS_CALL_POSSIBLE_H_
10 
11 namespace kw {
12 
18 template<typename Type>
21 class has_member {
22  class yes {
23  char m;
24  };
25 
26  class no {
27  yes m[2];
28  };
29 
32  void operator()() {}
33  };
34 
38  public Type,
39  public DummyFnCallOperator {
40  };
41 
44  template<typename T, T t>
45  class Helper {};
46 
54  template<typename U>
55  static no deduce(
56  U*, Helper<void (DummyFnCallOperator::*)(), &U::operator()>* = 0);
57 
60  static yes deduce(...);
61 
62  public:
63  static const bool result =
64  sizeof(yes) == sizeof(deduce((HasAtLeastOneFnCallOperator*) (0)));
65 };
66 
67 
68 namespace details {
69 
70 // If the operator matching the desired inputs returns void, then when
71 // we take a void expression and comma-operator it with one of these guys,
72 // the result will be one of these guys. This will lead to the overload
73 // resolution of a function taking this type as a parameter
74 template<typename type>
75 class void_exp_result {};
76 
77 template<typename type, typename U>
78 U const& operator,(U const&, void_exp_result<type>);
79 
80 template<typename type, typename U>
82 
84 template<typename src_type, typename dest_type>
86  typedef dest_type type;
87 };
88 
91 template<typename src_type, typename dest_type>
92 struct clone_constness<const src_type, dest_type> {
93  typedef const dest_type type;
94 };
95 
96 } // namespace details
97 
98 
99 template <typename type, typename call_details>
101 {
102 private:
103  class yes {};
104  class no {
105  yes m[2];
106  };
107 
113  struct derived : public type {
114  using type::operator();
115  no operator()(...) const;
116  };
117 
120 
124  template<typename T, typename DesiredReturnType>
126  // This overload will be resolved by the compiler if the function
127  // call operator matching the desired inputs returns anything that is
128  // convertable to `DesiredReturnType`.
129  static yes deduce(DesiredReturnType);
130 
131  // If the operator matching the desired input arguments returns anything
132  // other than void which is not convertable to a DesiredReturnType, then
133  // this is the overload that will be resolved by the compiler.
134  static no deduce(...);
135 
136  // If no operator matching the desired input arguments is found, then
137  // the operator() from derived that returns `no` will be the one that
138  // get's resolved below.
139  static no deduce(no);
140 
141  // If the operator matching the desired inputs returns void, then when
142  // we take a void expression and comma-operator it with one of
144  };
145 
149  template<typename T>
150  struct return_value_check<T, void> {
151  static yes deduce(...);
152  static no deduce(no);
153  };
154 
155  template <typename Mid, typename... Tail>
156  struct Dispatcher {
157  template <typename... Head>
158  static inline auto Dispatch( Head ... head)
159  -> decltype(Dispatcher<Tail...>::Dispatch(head..., (*(Mid*)0))) {
160  Dispatcher<Tail...>::Dispatch(head..., (*(Mid*) 0));
161  }
162  };
163 
164  template <typename Tail>
165  struct Dispatcher<Tail> {
166  template <typename... Head>
167  static inline auto Dispatch(Head... head)
168  -> decltype(((derived_type*) 0)->operator()(head..., (*(Tail*)0))){
169  ((derived_type*) 0)->operator()(head..., (*(Tail*)0));
170  }
171  };
172 
175  template<bool HasFnCallOperator, typename F>
176  struct impl {
177  static const bool value = false;
178  };
179 
180  template<typename... args, typename r>
181  struct impl<true, r(args...)> {
182  typedef Dispatcher<args...> CallDispatcher;
183  // The thing we're taking the `sizeof` here is a function call, so the
184  // `sizeof` call will evaluate to the `sizeof` the function's return type.
185  //
186  // The function being called is the deduce method of
187  // `return_value_check<type,r>`. The method resolved by this call will
188  // be the one that returns a `yes` object only if the parameter of
189  // `deduce()` is compatible with `r`.
190  //
191  // The parameter of `deduce` is a comma separated tuple of the return
192  // type of the function call operator and a `void_exp_result` object. If
193  // the function call operator returns void then this tuple resolves to
194  // be just the latter argument. Otherwise, the comma operator overload above
195  // passes through the return value of the function call operator.
196  static const bool value = sizeof(return_value_check<type, r>::deduce(
197  (CallDispatcher::Dispatch(), details::void_exp_result<
198  type>()))) == sizeof(yes);
199  };
200 
201  // specializations of impl for 2 args, 3 args,..
202  public:
203  static const bool value = impl<has_member<type>::result, call_details>::value;
204 };
205 
206 template <typename SourceType, typename TargetType>
208 {
209 private:
210  class Yes { char x; };
211  class No {
212  Yes m[2];
213  };
214 
215  // if SourceType is convertable to TargetType then this overload will be
216  // resolved when we call Deduce(SourceType)
217  static Yes Deduce(TargetType);
218 
219  // If it is not convertible, then this overload will be resolved.
220  static No Deduce(...);
221 
222 public:
223  static constexpr bool value = sizeof(Deduce(*(SourceType*)0)) == sizeof(Yes);
224 };
225 
226 
227 
228 
229 
230 } // namespace kw
231 
232 
233 
234 #endif /* IS_CALL_POSSIBLE_H_ */
static Yes Deduce(TargetType)
static const bool value
static const bool result
static yes deduce(DesiredReturnType)
A class which will definitely have a function call operator. If type has a function call operator the...
Provides a member function deduce() which accepts any parameters and whose return type is always no e...
static no deduce(U *, Helper< void(DummyFnCallOperator::*)(),&U::operator()>*=0)
SFINAE. The first overload for deduce takes two arguments, the first is a pointer to an object...
This template only exists for a pair of template parameters where the type of the second parameter is...
details::clone_constness< type, derived >::type derived_type
Same as derived but with the same const-ness as type.
static auto Dispatch(Head...head) -> decltype(Dispatcher< Tail...>::Dispatch(head...,(*(Mid *) 0)))
Template metafunction, ::result evaluates to true if Type has a function call operator member...
Default template, HasFnCallOperator is false so obviously no function call is possible.
static constexpr bool value
This class derives from both the argument of the meta function, and a class which we know has a funct...
Very simply, a class which has a function call operator.
Template meta function, copy's "const" from src_type to dest_type.
U const & operator,(U const &, void_exp_result< type >)
static auto Dispatch(Head...head) -> decltype(((derived_type *) 0) ->operator()(head...,(*(Tail *) 0)))