Lumiera  0.pre.03
»edit your freedom«
function-signature-test.cpp
Go to the documentation of this file.
1 /*
2  FunctionSignature(Test) - metaprogramming to extract function signature type
3 
4  Copyright (C)
5  2017, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
19 #include "lib/test/run.hpp"
20 #include "lib/format-cout.hpp"
21 #include "lib/format-util.hpp"
22 #include "lib/meta/function.hpp"
23 
24 #include <functional>
25 #include <string>
26 
27 
28 using std::function;
29 using std::placeholders::_1;
30 using std::bind;
31 using std::string;
32 using std::tuple;
33 using std::move;
34 
35 
36 namespace lib {
37 namespace meta {
38 namespace test {
39 
40  using lib::meta::_Fun;
41  using lib::meta::typeStr;
42 
43 
44  namespace { // test subjects
45 
46  int
47  freeFun (uint i)
48  {
49  return -i+1;
50  }
51 
52  struct Functor
53  {
54  int ii = 2;
55 
56  int
57  fun (uint i2)
58  {
59  return ii + freeFun(i2);
60  }
61 
62  int
63  operator() (uint i2)
64  {
65  return 2*ii - fun(i2);
66  }
67 
68  static int
69  staticFun (uint i)
70  {
71  return 2*freeFun (i);
72  }
73  };
74 
75 
76  /* ===== diagnostics helper ===== */
77 
78  template<typename F>
79  string
80  showSig (F)
81  {
82  return typeStr<typename _Fun<F>::Sig>();
83  }
84 
85  template<typename F>
86  string
87  showSigRef (F&)
88  {
89  return typeStr<typename _Fun<F>::Sig>();
90  }
91 
92  template<typename F>
93  string
94  showSigCRef (F&)
95  {
96  return typeStr<typename _Fun<F>::Sig>();
97  }
98 
99  template<typename F>
100  string
101  showSigRRef (F&&)
102  {
103  return typeStr<typename _Fun<F>::Sig>();
104  }
105 
106  } // (End) test subjects
107 
108 
109  using Func = function<int(uint)>;
110  using FuncF = function<int(Functor&, uint)>;
111 
112 
113 
114 
115 
116 
117  /*********************************************************************/
128  class FunctionSignature_test : public Test
129  {
130  virtual void
131  run (Arg)
132  {
133  // this is how the key trick of the _Fun traits template works:
134  // for anything "function like" we retrieve a member-pointer to the function call operator
135  // which we then pass on to the dedicated overload for member pointers
136  CHECK ("int (Functor::*)(uint)" == typeStr<decltype(&Functor::operator())>());
137 
138 
139  Func f1{freeFun};
140  Func f2{&freeFun};
141 
142  Func f3{Functor::staticFun};
143  Func f4{&Functor::staticFun};
144 
145 
146  Functor funk;
147 
148 
149  auto lambda = [&](uint ii) { return funk.fun(ii); };
150 
151  Func f5{lambda};
152 
153  CHECK ("int (uint)" == showSig (freeFun));
154  CHECK ("int (uint)" == showSig (&freeFun));
155  CHECK ("int (uint)" == showSig (Functor::staticFun));
156  CHECK ("int (uint)" == showSig (lambda));
157  CHECK ("int (uint)" == showSig (f5));
158 
159 
160  CHECK ("int (uint)" == showSigRef (freeFun));
161  CHECK ("int (uint)" == showSigRef (lambda));
162  CHECK ("int (uint)" == showSigRef (f5));
163 
164  CHECK ("int (uint)" == showSigCRef (freeFun));
165  CHECK ("int (uint)" == showSigCRef (lambda));
166  CHECK ("int (uint)" == showSigCRef (f5));
167 
168  CHECK ("int (uint)" == showSigRRef (move(lambda)));
169  CHECK ("int (uint)" == showSigRRef (move(f5)));
170 
171  CHECK ("int (uint)" == showSig (move(&freeFun)));
172  CHECK ("int (uint)" == showSig (move(lambda)));
173  CHECK ("int (uint)" == showSig (move(f5)));
174 
175 
176  Func& funRef = f1;
177  Functor& funkyRef = funk;
178  Func const& funCRef = f1;
179  Functor const& funkyCRef = funk;
180  CHECK ("int (uint)" == showSig (funRef));
181  CHECK ("int (uint)" == showSig (funkyRef));
182  CHECK ("int (uint)" == showSig (funCRef));
183  CHECK ("int (uint)" == showSig (funkyCRef));
184 
185 
186  CHECK ("int (uint)" == typeStr<_Fun<int(uint)>::Sig >());
187  CHECK ("int (uint)" == typeStr<_Fun<Func&>::Sig >());
188  CHECK ("int (uint)" == typeStr<_Fun<Func&&>::Sig >());
189  CHECK ("int (uint)" == typeStr<_Fun<Func const&>::Sig >());
190  CHECK ("int (uint)" == typeStr<_Fun<Functor&>::Sig >());
191  CHECK ("int (uint)" == typeStr<_Fun<Functor&&>::Sig >());
192  CHECK ("int (uint)" == typeStr<_Fun<Functor const&>::Sig>());
193 
194  using Siggy = _Fun<Func>::Sig;
195  CHECK ("int (uint)" == typeStr<_Fun<Siggy&>::Sig >());
196  CHECK ("int (uint)" == typeStr<_Fun<Siggy&&>::Sig >());
197  CHECK ("int (uint)" == typeStr<_Fun<Siggy const&>::Sig >());
198 
199 
200  auto memfunP = &Functor::fun;
201  FuncF fM{memfunP};
202  Func fMF{bind (fM, funk, _1)};
203 
204  CHECK ("int (uint)" == typeStr<_Fun<decltype(memfunP)>::Sig>());
205  CHECK ("int (Functor&, uint)" == typeStr<_Fun<decltype(fM)>::Sig >());
206  CHECK ("int (uint)" == typeStr<_Fun<decltype(fMF)>::Sig >());
207 
208 
209  // _Fun<F> can be used for metaprogramming with enable_if
210  CHECK ( _Fun<Func>::value); // yes : a Functor
211  CHECK ( _Fun<int(long)>::value); // yes : a function type
212  CHECK (not _Fun<int>::value); // no : a type without function call operator
213 
214  auto lambda1 = [](int i) { return double(i) / (i*i); };
215  auto lambda2 = [](auto i) { return double(i) / (i*i); };
216 
217  using TLamb1 = decltype(lambda1);
218  using TLamb2 = decltype(lambda2);
219 
220  CHECK ( _Fun<TLamb1>::value); // yes : detect signature of lambda
221  CHECK (not _Fun<TLamb2>::value); // no : can not detect signature of a generic lambda!
222 
223  // but detection works, once the templated operator() has been instantiated to some fixed type
224  auto stdFunction = function<double(float)> (lambda2);
225  CHECK ( _Fun<decltype(stdFunction)>::value);
226 
227  CHECK ("double (int)" == showSig (lambda1));
228  CHECK ("double (float)" == showSig (stdFunction));
229  }
230  };
231 
232 
234  LAUNCHER (FunctionSignature_test, "unit common");
235 
236 
237 
238 }}} // namespace lib::meta::test
Automatically use custom string conversion in C++ stream output.
Definition: run.hpp:40
Helper for uniform access to function signature types.
Definition: function.hpp:99
Implementation namespace for support and library code.
Metaprogramming tools for transforming functor types.
Simplistic test class runner.
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
std::string typeStr(TY const *obj=nullptr) noexcept
failsafe human readable type display
Definition: meta/util.hpp:316