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) Lumiera.org
5  2017, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
28 #include "lib/test/run.hpp"
29 #include "lib/format-cout.hpp"
30 #include "lib/format-util.hpp"
31 #include "lib/meta/function.hpp"
32 
33 #include <functional>
34 #include <string>
35 
36 
37 using std::function;
38 using std::placeholders::_1;
39 using std::bind;
40 using std::string;
41 using std::tuple;
42 using std::move;
43 
44 
45 namespace lib {
46 namespace meta {
47 namespace test {
48 
49  using lib::meta::_Fun;
50  using lib::meta::typeStr;
51 
52 
53  namespace { // test subjects
54 
55  int
56  freeFun (uint i)
57  {
58  return -i+1;
59  }
60 
61  struct Functor
62  {
63  int ii = 2;
64 
65  int
66  fun (uint i2)
67  {
68  return ii + freeFun(i2);
69  }
70 
71  int
72  operator() (uint i2)
73  {
74  return 2*ii - fun(i2);
75  }
76 
77  static int
78  staticFun (uint i)
79  {
80  return 2*freeFun (i);
81  }
82  };
83 
84 
85  /* ===== diagnostics helper ===== */
86 
87  template<typename F>
88  string
89  showSig (F)
90  {
91  return typeStr<typename _Fun<F>::Sig>();
92  }
93 
94  template<typename F>
95  string
96  showSigRef (F&)
97  {
98  return typeStr<typename _Fun<F>::Sig>();
99  }
100 
101  template<typename F>
102  string
103  showSigCRef (F&)
104  {
105  return typeStr<typename _Fun<F>::Sig>();
106  }
107 
108  template<typename F>
109  string
110  showSigRRef (F&&)
111  {
112  return typeStr<typename _Fun<F>::Sig>();
113  }
114 
115  } // (End) test subjects
116 
117 
118  using Func = function<int(uint)>;
119  using FuncF = function<int(Functor&, uint)>;
120 
121 
122 
123 
124 
125 
126  /*********************************************************************/
137  class FunctionSignature_test : public Test
138  {
139  virtual void
140  run (Arg)
141  {
142  // this is how the key trick of the _Fun traits template works:
143  // for anything "function like" we retrieve a member-pointer to the function call operator
144  // which we then pass on to the dedicated overload for member pointers
145  CHECK ("int (Functor::*)(unsigned int)" == typeStr<decltype(&Functor::operator())>());
146 
147 
148  Func f1{freeFun};
149  Func f2{&freeFun};
150 
151  Func f3{Functor::staticFun};
152  Func f4{&Functor::staticFun};
153 
154 
155  Functor funk;
156 
157 
158  auto lambda = [&](uint ii) { return funk.fun(ii); };
159 
160  Func f5{lambda};
161 
162  CHECK ("int (unsigned int)" == showSig (freeFun));
163  CHECK ("int (unsigned int)" == showSig (&freeFun));
164  CHECK ("int (unsigned int)" == showSig (Functor::staticFun));
165  CHECK ("int (unsigned int)" == showSig (lambda));
166  CHECK ("int (unsigned int)" == showSig (f5));
167 
168 
169  CHECK ("int (unsigned int)" == showSigRef (freeFun));
170  CHECK ("int (unsigned int)" == showSigRef (lambda));
171  CHECK ("int (unsigned int)" == showSigRef (f5));
172 
173  CHECK ("int (unsigned int)" == showSigCRef (freeFun));
174  CHECK ("int (unsigned int)" == showSigCRef (lambda));
175  CHECK ("int (unsigned int)" == showSigCRef (f5));
176 
177  CHECK ("int (unsigned int)" == showSigRRef (move(lambda)));
178  CHECK ("int (unsigned int)" == showSigRRef (move(f5)));
179 
180  CHECK ("int (unsigned int)" == showSig (move(&freeFun)));
181  CHECK ("int (unsigned int)" == showSig (move(lambda)));
182  CHECK ("int (unsigned int)" == showSig (move(f5)));
183 
184 
185  Func& funRef = f1;
186  Functor& funkyRef = funk;
187  Func const& funCRef = f1;
188  Functor const& funkyCRef = funk;
189  CHECK ("int (unsigned int)" == showSig (funRef));
190  CHECK ("int (unsigned int)" == showSig (funkyRef));
191  CHECK ("int (unsigned int)" == showSig (funCRef));
192  CHECK ("int (unsigned int)" == showSig (funkyCRef));
193 
194 
195  CHECK ("int (unsigned int)" == typeStr<_Fun<int(uint)>::Sig >());
196  CHECK ("int (unsigned int)" == typeStr<_Fun<Func&>::Sig >());
197  CHECK ("int (unsigned int)" == typeStr<_Fun<Func&&>::Sig >());
198  CHECK ("int (unsigned int)" == typeStr<_Fun<Func const&>::Sig >());
199  CHECK ("int (unsigned int)" == typeStr<_Fun<Functor&>::Sig >());
200  CHECK ("int (unsigned int)" == typeStr<_Fun<Functor&&>::Sig >());
201  CHECK ("int (unsigned int)" == typeStr<_Fun<Functor const&>::Sig>());
202 
203  using Siggy = _Fun<Func>::Sig;
204  CHECK ("int (unsigned int)" == typeStr<_Fun<Siggy&>::Sig >());
205  CHECK ("int (unsigned int)" == typeStr<_Fun<Siggy&&>::Sig >());
206  CHECK ("int (unsigned int)" == typeStr<_Fun<Siggy const&>::Sig >());
207 
208 
209  auto memfunP = &Functor::fun;
210  FuncF fM{memfunP};
211  Func fMF{bind (fM, funk, _1)};
212 
213  CHECK ("int (unsigned int)" == typeStr<_Fun<decltype(memfunP)>::Sig>());
214  CHECK ("int (Functor&, unsigned int)" == typeStr<_Fun<decltype(fM)>::Sig >());
215  CHECK ("int (unsigned int)" == typeStr<_Fun<decltype(fMF)>::Sig >());
216 
217 
218  // _Fun<F> can be used for metaprogramming with enable_if
219  CHECK ( _Fun<Func>::value); // yes : a Functor
220  CHECK ( _Fun<int(long)>::value); // yes : a function type
221  CHECK (not _Fun<int>::value); // no : a type without function call operator
222 
223  auto lambda1 = [](int i) { return double(i) / (i*i); };
224  auto lambda2 = [](auto i) { return double(i) / (i*i); };
225 
226  using TLamb1 = decltype(lambda1);
227  using TLamb2 = decltype(lambda2);
228 
229  CHECK ( _Fun<TLamb1>::value); // yes : detect signature of lambda
230  CHECK (not _Fun<TLamb2>::value); // no : can not detect signature of a generic lambda!
231 
232  // but detection works, once the templated operator() has been instantiated to some fixed type
233  auto stdFunction = function<double(float)> (lambda2);
234  CHECK ( _Fun<decltype(stdFunction)>::value);
235 
236  CHECK ("double (int)" == showSig (lambda1));
237  CHECK ("double (float)" == showSig (stdFunction));
238  }
239  };
240 
241 
243  LAUNCHER (FunctionSignature_test, "unit common");
244 
245 
246 
247 }}} // namespace lib::meta::test
Automatically use custom string conversion in C++ stream output.
Definition: run.hpp:49
Helper for uniform access to function signature types.
Definition: function.hpp:108
Implementation namespace for support and library code.
Metaprogramming tools for transforming functor types.
Simple 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:325