c++-gtk-utils

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

do_if.h
Go to the documentation of this file.
1 /* Copyright (C) 2010 to 2013 Chris Vine
2
3 The library comprised in this file or of which this file is part is
4 distributed by Chris Vine under the GNU Lesser General Public
5 License as follows:
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public License
9 as published by the Free Software Foundation; either version 2.1 of
10 the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License, version 2.1, for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License, version 2.1, along with this library (see the file LGPL.TXT
19 which came with this source code package in the c++-gtk-utils
20 sub-directory); if not, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23 However, it is not intended that the object code of a program whose
24 source code instantiates a template from this file or uses macros or
25 inline functions (of any length) should by reason only of that
26 instantiation or use be subject to the restrictions of use in the GNU
27 Lesser General Public License. With that in mind, the words "and
28 macros, inline functions and instantiations of templates (of any
29 length)" shall be treated as substituted for the words "and small
30 macros and small inline functions (ten lines or less in length)" in
31 the fourth paragraph of section 5 of that licence. This does not
32 affect any other reason why object code may be subject to the
33 restrictions in that licence (nor for the avoidance of doubt does it
34 affect the application of section 2 of that licence to modifications
35 of the source code in this file).
36
37 */
38
39 #ifndef CGU_DO_IF_H
40 #define CGU_DO_IF_H
41
42 /**
43 * @file do_if.h
44 * @brief This file provides utility functions for conditional compilation.
45 *
46 * \#include <c++-gtk-utils/do_if.h>
47 *
48 * The DoIf namespace of the library provides a small subset of
49 * template meta-programming techniques likely to be most relevant to
50 * GUI programming (if something more substantial is required,
51 * something like boost or loki should be used).
52 *
53 * For conditional compilation, the library provides the
54 * Cgu::DoIf::mem_fun() utility functions which will conditionally
55 * compile a call to a non-static class member function if, and only
56 * if, the target object has that function as a member. If it does
57 * not have the member function as a member, the call will just do
58 * nothing rather than generate a compiler error, as it will also if
59 * the target object is const and the member function to be called is
60 * non-const. In addition Cgu::DoIf::fun() will conditionally compile
61 * a call to an ordinary function (or static member function) if, and
62 * only if, the target object is convertible to the type (say, a base
63 * type) held by pointer as the first argument of that function.
64 *
65 * They therefore provide compile-time inheritance checking based on
66 * the static type of the object passed to them. They save dynamic
67 * casting (and therefore run time overhead and the requirement for
68 * target types to have a virtual method) in templated functions when
69 * the static type is all that is necessary to enable type checking to
70 * be carried out.
71 *
72 * This is not just a template curiosity, but enables more generic
73 * programming practices when, say, passing mixins to templated
74 * functions. A templated function can be passed an object as a
75 * template type, and that function can then conditionally call member
76 * functions of objects passed to it. If the object has a particular
77 * function as a member, Cgu::DoIf::mem_fun() will call the function,
78 * and if not it will do nothing without causing a compilation error.
79 * It can be particularly useful for templated set-up or tear-down
80 * functions intended to take a wide variety of different objects with
81 * differing features.
82 *
83 * As mentioned above, Cgu::DoIf::mem_fun() and Cgu::DoIf::fun() will
84 * do nothing if an attempt is made to execute a non-const function on
85 * a const object, as well as if the object type does not match the
86 * function or member function sought to be invoked. If a compilation
87 * failure is wanted in a case of const mismatch instead of doing
88 * nothing, from version 2.0.1 the static assertion
89 * Cgu::DoIf::assert_not_const() can be invoked before the call to a
90 * non-const function is made by Cgu::DoIf::mem_fun() or
91 * Cgu::DoIf::fun().
92 *
93 * Non-static member functions
94 * ---------------------------
95 *
96 * The first argument to be passed to Cgu::DoIf::mem_fun() is the
97 * target object to be tested and the second argument is the
98 * non-static member function which is to be called with respect to
99 * that object if it has the function as a member. Any number of
100 * further arguments can be passed, representing the arguments to be
101 * provided to that member function. These further arguments may be
102 * reference arguments (const or non-const), value arguments or
103 * r-values, and for automatic pass-through they are passed by r-value
104 * reference and std::forward(), so no overhead should be created if
105 * value or r-value arguments are passed via Cgu::DoIf::mem_fun().
106 *
107 * As an example, take a class which uses multiple inheritance to
108 * inherit from Cgu::EmitterArg as a mixin (normally a class would
109 * have an Emitter object as a member, but it can be inherited from).
110 * A container of objects could have the emit() method called on them
111 * in a case where they do inherit from EmitterArg, where the code
112 * does nothing if they do not. For example:
113 * @code
114 * class Calc {
115 * public:
116 * void do_calc(void);
117 * };
118 *
119 * class CalcEmit: public Calc,
120 * public Cgu::EmitterArg<int> {
121 * };
122 *
123 * ... some code blocks elsewhere ...
124 *
125 * template <class T>
126 * void dispatch_calcs(const std::vector<T>& v) {
127 * int count;
128 * typename std::vector<T>::const_iterator iter;
129 * for (count = 0, iter = v.begin();
130 * iter != v.end();
131 * ++count, ++iter) {
132 * iter->do_calc();
133 * Cgu::DoIf::mem_fun(*iter, // object to be tested
134 * &Cgu::EmitterArg<int>::emit, // member function to be conditionally called
135 * count); // argument
136 * }
137 * }
138 * @endcode
139 *
140 * Ordinary functions and static member functions
141 * ----------------------------------------------
142 *
143 * The use of Cgu::DoIf::fun() with normal functions and static member
144 * functions is similar to the use of mem_fun() with non-static member
145 * functions, except that the first argument of the function to be
146 * conditionally called must be a pointer to a type to which the
147 * target object can prospectively be converted. The first argument
148 * to be passed to Cgu::DoIf::fun() is the target object to be tested
149 * and the second argument is the function which is to be
150 * conditionally called if the conversion can be accomplished. If the
151 * function to be conditionally called is so called, the target object
152 * will be passed by pointer to it. Any number of further arguments
153 * can be passed to Cgu::DoIf::fun(), representing additional
154 * arguments to be provided to the function to be conditionally
155 * called, which may be reference arguments, value arguments or
156 * r-value reference arguments (and automatic pass-through is
157 * provided, as in the case of mem_fun()).
158 *
159 * The use of Cgu::DoIf::fun() with ordinary functions can be useful
160 * for batching a number of calls to be made to a test object. For
161 * example:
162 *
163 * @code
164 * class Calc {
165 * public:
166 * void do_calc();
167 * };
168 *
169 * class CalcEmit: public Calc,
170 * public Cgu::EmitterArg<int> {
171 * public:
172 * void clean_up(int);
173 * };
174 *
175 * ... some code blocks elsewhere ...
176 *
177 * void emit_on_calcs(CalcEmit* c, int count) {
178 * c->emit(count);
179 * c->clean_up(count);
180 * }
181 *
182 * template <class T>
183 * void dispatch_calcs(const std::vector<T>& v) {
184 * int count;
185 * typename std::vector<T>::const_iterator iter;
186 * for (count = 0, iter = v.begin();
187 * iter != v.end();
188 * ++count, ++iter) {
189 * iter->do_calc();
190 * Cgu::DoIf::fun(*iter, // object to be tested against first argument of function to be conditionally called
191 * &emit_on_calcs, // function to be conditionally called
192 * count); // second argument of function to be conditionally called
193 * }
194 * }
195 * @endcode
196 *
197 * Return values
198 * -------------
199 *
200 * If the function to be called returns something other than void and
201 * the function to be conditionally called is not called, then
202 * mem_fun() and fun() pass back a dummy object of the return type
203 * using that type's default constructor. The returned object has no
204 * meaning beyond that in such a case, so it should not be relied on
205 * as holding anything other than its default value on default
206 * construction in a case of failure. This in turn means that any
207 * return value, if not a built-in type, must have a default
208 * constructor.
209 *
210 * Overloaded functions
211 * --------------------
212 *
213 * Where a referenced member function or ordinary function is
214 * overloaded, this will cause difficulties in template type deduction
215 * when mem_fun() or fun() is called, requiring explicit
216 * disambiguation. For example the following will fail to compile
217 * unless explicitly disambiguated:
218 * @code
219 * class A {
220 * public:
221 * void do_it(int i);
222 * void do_it(int i, int j);
223 * void do_it(double d);
224 * };
225 * int func(A* a, int i);
226 * int func(A* a, double d);
227 *
228 * template <class T>
229 * void do_it_if(T& t) {
230 * int i = 1, j = 2;
231 * double d = 10.0;
232 * Cgu::DoIf::mem_fun(t, &A::do_it, i); // won't compile
233 * Cgu::DoIf::mem_fun(t, &A::do_it, i, j); // won't compile
234 * Cgu::DoIf::mem_fun(t, &A::do_it, d); // won't compile
235 * Cgu::DoIf::fun(t, func, i); // won't compile
236 * Cgu::DoIf::fun(t, func, d); // won't compile
237 *
238 * Cgu::DoIf::mem_fun(t, static_cast<void (A::*)(int)>(&A::do_it), i); // OK
239 * Cgu::DoIf::mem_fun(t, static_cast<void (A::*)(int, int)>(&A::do_it), i, j); // OK
240 * Cgu::DoIf::mem_fun(t, static_cast<void (A::*)(double)>(&A::do_it), d); // OK
241 * Cgu::DoIf::fun(t, static_cast<int (*)(A*, int)>(func), i); // OK
242 * Cgu::DoIf::fun(t, static_cast<int (*)(A*, double)>(func), d); // OK
243 * }
244 * @endcode
245 *
246 * Static assertion
247 * ----------------
248 *
249 * This library also provides the Cgu::DoIf::assert_related_to_type(),
250 * Cgu::DoIf::assert_related_types() and Cgu::DoIf::assert_same_type()
251 * static type-checking assertions. If the matters asserted are not
252 * true, a compile time error in the line where the functions are
253 * instantiated will occur.
254 *
255 * These static assertion functions can be viewed as doing the
256 * opposite of Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(). The
257 * mem_fun() and fun() functions will make a conditional call, and do
258 * nothing if the test condition is not met without a compile time or
259 * run time error, in order to provide compile time polymorphism. On
260 * the other hand, assert_related_to_type(), assert_related_types()
261 * and assert_same_type() cause an explicit compilation error where
262 * the test condition is not met at an ascertainable point in the code
263 * whilst avoiding a slew of incomprehensible error messages from the
264 * compiler. They enable compile time checking of type related
265 * invariants.
266 *
267 * In addition, from version 2.0.1, a Cgu::DoIf::assert_not_const()
268 * static assertion is available.
269 *
270 * The static assertions add nothing to the compiled object code.
271 * They either succeed or fail at compile time.
272 */
273
274 /**
275 * @namespace Cgu::DoIf
276 * @brief This namespace provides utility functions for conditional compilation.
277 *
278 * \#include <c++-gtk-utils/do_if.h>
279 *
280 * The DoIf namespace of the library provides a small subset of
281 * template meta-programming techniques likely to be most relevant to
282 * GUI programming (if something more substantial is required,
283 * something like boost or loki should be used).
284 *
285 * For conditional compilation, the library provides the
286 * Cgu::DoIf::mem_fun() utility functions which will conditionally
287 * compile a call to a non-static class member function if, and only
288 * if, the target object has that function as a member. If it does
289 * not have the member function as a member, the call will just do
290 * nothing rather than generate a compiler error, as it will also if
291 * the target object is const and the member function to be called is
292 * non-const. In addition Cgu::DoIf::fun() will conditionally compile
293 * a call to an ordinary function (or static member function) if, and
294 * only if, the target object is convertible to the type (say, a base
295 * type) held by pointer as the first argument of that function.
296 *
297 * They therefore provide compile-time inheritance checking based on
298 * the static type of the object passed to them. They save dynamic
299 * casting (and therefore run time overhead and the requirement for
300 * target types to have a virtual method) in templated functions when
301 * the static type is all that is necessary to enable type checking to
302 * be carried out.
303 *
304 * This is not just a template curiosity, but enables more generic
305 * programming practices when, say, passing mixins to templated
306 * functions. A templated function can be passed an object as a
307 * template type, and that function can then conditionally call member
308 * functions of objects passed to it. If the object has a particular
309 * function as a member, Cgu::DoIf::mem_fun() will call the function,
310 * and if not it will do nothing without causing a compilation error.
311 * It can be particularly useful for templated set-up or tear-down
312 * functions intended to take a wide variety of different objects with
313 * differing features.
314 *
315 * As mentioned above, Cgu::DoIf::mem_fun() and Cgu::DoIf::fun() will
316 * do nothing if an attempt is made to execute a non-const function on
317 * a const object, as well as if the object type does not match the
318 * function or member function sought to be invoked. If a compilation
319 * failure is wanted in a case of const mismatch instead of doing
320 * nothing, from version 2.0.1 the static assertion
321 * Cgu::DoIf::assert_not_const() can be invoked before the call to a
322 * non-const function is made by Cgu::DoIf::mem_fun() or
323 * Cgu::DoIf::fun().
324 *
325 * Non-static member functions
326 * ---------------------------
327 *
328 * The first argument to be passed to Cgu::DoIf::mem_fun() is the
329 * target object to be tested and the second argument is the
330 * non-static member function which is to be called with respect to
331 * that object if it has the function as a member. Any number of
332 * further arguments can be passed, representing the arguments to be
333 * provided to that member function. These further arguments may be
334 * reference arguments (const or non-const), value arguments or
335 * r-values, and for automatic pass-through they are passed by r-value
336 * reference and std::forward(), so no overhead should be created if
337 * value or r-value arguments are passed via Cgu::DoIf::mem_fun().
338 *
339 * As an example, take a class which uses multiple inheritance to
340 * inherit from Cgu::EmitterArg as a mixin (normally a class would
341 * have an Emitter object as a member, but it can be inherited from).
342 * A container of objects could have the emit() method called on them
343 * in a case where they do inherit from EmitterArg, where the code
344 * does nothing if they do not. For example:
345 * @code
346 * class Calc {
347 * public:
348 * void do_calc(void);
349 * };
350 *
351 * class CalcEmit: public Calc,
352 * public Cgu::EmitterArg<int> {
353 * };
354 *
355 * ... some code blocks elsewhere ...
356 *
357 * template <class T>
358 * void dispatch_calcs(const std::vector<T>& v) {
359 * int count;
360 * typename std::vector<T>::const_iterator iter;
361 * for (count = 0, iter = v.begin();
362 * iter != v.end();
363 * ++count, ++iter) {
364 * iter->do_calc();
365 * Cgu::DoIf::mem_fun(*iter, // object to be tested
366 * &Cgu::EmitterArg<int>::emit, // member function to be conditionally called
367 * count); // argument
368 * }
369 * }
370 * @endcode
371 *
372 * Ordinary functions and static member functions
373 * ----------------------------------------------
374 *
375 * The use of Cgu::DoIf::fun() with normal functions and static member
376 * functions is similar to the use of mem_fun() with non-static member
377 * functions, except that the first argument of the function to be
378 * conditionally called must be a pointer to a type to which the
379 * target object can prospectively be converted. The first argument
380 * to be passed to Cgu::DoIf::fun() is the target object to be tested
381 * and the second argument is the function which is to be
382 * conditionally called if the conversion can be accomplished. If the
383 * function to be conditionally called is so called, the target object
384 * will be passed by pointer to it. Any number of further arguments
385 * can be passed to Cgu::DoIf::fun(), representing additional
386 * arguments to be provided to the function to be conditionally
387 * called, which may be reference arguments, value arguments or
388 * r-value reference arguments (and automatic pass-through is
389 * provided, as in the case of mem_fun()).
390 *
391 * The use of Cgu::DoIf::fun() with ordinary functions can be useful
392 * for batching a number of calls to be made to a test object. For
393 * example:
394 *
395 * @code
396 * class Calc {
397 * public:
398 * void do_calc();
399 * };
400 *
401 * class CalcEmit: public Calc,
402 * public Cgu::EmitterArg<int> {
403 * public:
404 * void clean_up(int);
405 * };
406 *
407 * ... some code blocks elsewhere ...
408 *
409 * void emit_on_calcs(CalcEmit* c, int count) {
410 * c->emit(count);
411 * c->clean_up(count);
412 * }
413 *
414 * template <class T>
415 * void dispatch_calcs(const std::vector<T>& v) {
416 * int count;
417 * typename std::vector<T>::const_iterator iter;
418 * for (count = 0, iter = v.begin();
419 * iter != v.end();
420 * ++count, ++iter) {
421 * iter->do_calc();
422 * Cgu::DoIf::fun(*iter, // object to be tested against first argument of function to be conditionally called
423 * &emit_on_calcs, // function to be conditionally called
424 * count); // second argument of function to be conditionally called
425 * }
426 * }
427 * @endcode
428 *
429 * Return values
430 * -------------
431 *
432 * If the function to be called returns something other than void and
433 * the function to be conditionally called is not called, then
434 * mem_fun() and fun() pass back a dummy object of the return type
435 * using that type's default constructor. The returned object has no
436 * meaning beyond that in such a case, so it should not be relied on
437 * as holding anything other than its default value on default
438 * construction in a case of failure. This in turn means that any
439 * return value, if not a built-in type, must have a default
440 * constructor.
441 *
442 * Overloaded functions
443 * --------------------
444 *
445 * Where a referenced member function or ordinary function is
446 * overloaded, this will cause difficulties in template type deduction
447 * when mem_fun() or fun() is called, requiring explicit
448 * disambiguation. For example the following will fail to compile
449 * unless explicitly disambiguated:
450 * @code
451 * class A {
452 * public:
453 * void do_it(int i);
454 * void do_it(int i, int j);
455 * void do_it(double d);
456 * };
457 * int func(A* a, int i);
458 * int func(A* a, double d);
459 *
460 * template <class T>
461 * void do_it_if(T& t) {
462 * int i = 1, j = 2;
463 * double d = 10.0;
464 * Cgu::DoIf::mem_fun(t, &A::do_it, i); // won't compile
465 * Cgu::DoIf::mem_fun(t, &A::do_it, i, j); // won't compile
466 * Cgu::DoIf::mem_fun(t, &A::do_it, d); // won't compile
467 * Cgu::DoIf::fun(t, func, i); // won't compile
468 * Cgu::DoIf::fun(t, func, d); // won't compile
469 *
470 * Cgu::DoIf::mem_fun(t, static_cast<void (A::*)(int)>(&A::do_it), i); // OK
471 * Cgu::DoIf::mem_fun(t, static_cast<void (A::*)(int, int)>(&A::do_it), i, j); // OK
472 * Cgu::DoIf::mem_fun(t, static_cast<void (A::*)(double)>(&A::do_it), d); // OK
473 * Cgu::DoIf::fun(t, static_cast<int (*)(A*, int)>(func), i); // OK
474 * Cgu::DoIf::fun(t, static_cast<int (*)(A*, double)>(func), d); // OK
475 * }
476 * @endcode
477 *
478 * Static assertion
479 * ----------------
480 *
481 * This library also provides the Cgu::DoIf::assert_related_to_type(),
482 * Cgu::DoIf::assert_related_types() and Cgu::DoIf::assert_same_type()
483 * static type-checking assertions. If the matters asserted are not
484 * true, a compile time error in the line where the functions are
485 * instantiated will occur.
486 *
487 * These static assertion functions can be viewed as doing the
488 * opposite of Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(). The
489 * mem_fun() and fun() functions will make a conditional call, and do
490 * nothing if the test condition is not met without a compile time or
491 * run time error, in order to provide compile time polymorphism. On
492 * the other hand, assert_related_to_type(), assert_related_types()
493 * and assert_same_type() cause an explicit compilation error where
494 * the test condition is not met at an ascertainable point in the code
495 * whilst avoiding a slew of incomprehensible error messages from the
496 * compiler. They enable compile time checking of type related
497 * invariants.
498 *
499 * In addition, from version 2.0.1, a Cgu::DoIf::assert_not_const()
500 * static assertion is available.
501 *
502 * The static assertions add nothing to the compiled object code.
503 * They either succeed or fail at compile time.
504 */
505
506 #include <utility> // for std::forward
507 #include <type_traits> // for std::true_type, std::false_type and std::remove_const
508
509 #include <c++-gtk-utils/cgu_config.h>
510
511 namespace Cgu {
512
513 namespace DoIf {
514
515 /**
516 * @class RelatedTest do_if.h c++-gtk-utils/do_if.h
517 * @brief Class for compile time testing of inheritance relationships
518 * @sa DoIf::mem_fun DoIf::fun
519 *
520 * This class provides a compile time test of whether the Obj class
521 * template parameter type is related to the Base class template
522 * parameter type by public derivation, or they are of the same type:
523 * the 'value' public member will be true if they are, otherwise
524 * false. Everything in it comprises a compile time constant so that
525 * 'value' can be used as a template parameter for conditional
526 * complation, and can also be used with the std::enable_if template.
527 *
528 * This class tests convertibility, and constness is not discarded in
529 * making the test. Whilst a non-const type passed as the second
530 * template parameter will (if the other conditions referred to above
531 * are met) be shown as related to a const base type or const same
532 * type specified as the first template parameter type, the reverse is
533 * not true. This ensures that the DoIf::mem_fun() and DoIf::fun()
534 * conditional compilation functions work correctly.
535 */
536
537 template<class Base, class Obj>
538 class RelatedTest {
539
540 static std::true_type test(Base*);
541 static std::false_type test(...);
542
543 typedef decltype(test(static_cast<Obj*>(0))) TestObjType;
544 typedef decltype(test(static_cast<void*>(0))) TestVoidType;
545
546 public:
547 /**
548 * A compile time constant which indicates whether the Obj class
549 * template parameter type is related to the Base class template
550 * parameter type by public derivation, or they are of the same type.
551 * Because it is a compile time constant it can be used as a template
552 * parameter and therefore for conditional compilation.
553 *
554 * This constant specifies convertibility, and constness is not
555 * discarded in making the test. Whilst a non-const type passed as
556 * the second template parameter will (if the other conditions
557 * referred to above are met) be shown as related to a const base type
558 * or const same type specified as the first template parameter type,
559 * the reverse is not true. This ensures that the DoIf::mem_fun() and
560 * DoIf::fun() conditional compilation functions work correctly.
561 */
562 static const bool value = TestObjType::value == true
563 && TestVoidType::value == false;
564 };
565
566 /**
567 * This function provides a compile time assertion that the static
568 * type of the second argument passed to it is related to (that is,
569 * either the same as or publicly derived from) the static type of the
570 * first argument. If it is not, a compile time error will occur
571 * (with a message that "Cgu::DoIf::assert_related_to_type() failed",
572 * and the line at which this function is reported as instantiated
573 * will be the line at which the assertion failed).
574 *
575 * For example "Cgu::DoIf::assert_related_to_type(a, b)" will fail to
576 * compile unless the static type of 'b' is the same as or publicly
577 * derived from the static type of 'a'. In making this test,
578 * constness is discarded and not taken into account.
579 *
580 * See assert_related_types() for a test where the ordering of the
581 * arguments is not significant.
582 *
583 * This function can be viewed as doing the opposite of
584 * Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(): it causes a compilation
585 * error where the test is not met, rather than doing nothing.
586 * However, unlike those functions, as mentioned above
587 * assert_related_to_type() discards constness in making the test.
588 *
589 * It generates no object code, and is therefore thread safe and does
590 * not throw.
591 */
592 template <class Base, class Obj>
593 void assert_related_to_type(const Base& b, const Obj& o) noexcept {
594 static_assert(RelatedTest<Base, Obj>::value,
595 "Cgu::DoIf::assert_related_to_type() failed");
596 }
597
598 /**
599 * This function provides a compile time assertion that the static
600 * type of the argument passed to it is related to (that is, either
601 * the same as or publicly derived from) the type given as the
602 * explicit template parameter to the function call. If it is not, a
603 * compile time error will occur (with a message that
604 * "Cgu::DoIf::assert_related_to_type() failed", and the line at which
605 * this function is reported as instantiated will be the line at which
606 * the assertion failed).
607 *
608 * For example "Cgu::DoIf::assert_related_to_type<A>(x)" will fail to
609 * compile unless the static type of 'x' is the same as or publicly
610 * derived from type A. In making this test, constness is discarded
611 * and not taken into account.
612 *
613 * This function can be viewed as doing the opposite of
614 * Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(): it causes a compilation
615 * error where the test is not met, rather than doing nothing.
616 * However, unlike those functions, as mentioned above
617 * assert_related_to_type() discards constness in making the test.
618 *
619 * It generates no object code, and is therefore thread safe and does
620 * not throw.
621 */
622 template <class Base, class Obj>
623 void assert_related_to_type(const Obj& o) noexcept {
624 static_assert(RelatedTest<Base, Obj>::value,
625 "Cgu::DoIf::assert_related_to_type() failed");
626 }
627
628 /**
629 * This function provides a compile time assertion that the static
630 * type of the first argument passed to it is the same as the static
631 * type of the second argument. If it is not, a compile time error
632 * will occur (with a message that "Cgu::DoIf::assert_same_type()
633 * failed", and the line at which this function is reported as
634 * instantiated will be the line at which the assertion failed).
635 *
636 * For example "Cgu::DoIf::assert_same_type(a, b)" will fail to
637 * compile unless the static types of 'a' and 'b' are the same. In
638 * making this test, constness is discarded and not taken into
639 * account: types can be the same even if one is const and the other
640 * is not.
641 *
642 * It generates no object code, and is therefore thread safe and does
643 * not throw.
644 */
645 template <class T1, class T2>
646 void assert_same_type(const T1& t1, const T2& t2) noexcept {
647 static_assert(RelatedTest<T1, T2>::value && RelatedTest<T2, T1>::value,
648 "Cgu::DoIf::assert_same_type() failed");
649 }
650
651 /**
652 * This function provides a compile time assertion that the static
653 * type of the argument passed to it is the same as the type given as
654 * the explicit template parameter to the function call. If it is
655 * not, a compile time error will occur (with a message that
656 * "Cgu::DoIf::assert_same_type() failed", and the line at which this
657 * function is reported as instantiated will be the line at which the
658 * assertion failed).
659 *
660 * For example "Cgu::DoIf::assert_same_type<A>(x)" will fail to
661 * compile unless the static type of 'x' is type A. In making this
662 * test, constness is discarded and not taken into account: types can
663 * be the same even if one is const and the other is not.
664 *
665 * It generates no object code, and is therefore thread safe and does
666 * not throw.
667 *
668 * Earlier versions of this function had a bug. A const type could
669 * not be specified as the explicit template argument
670 * (Cgu::DoIf::assert_same_type<const A>(x) would not work). This was
671 * fixed in version 2.0.1.
672 */
673 template <class T1, class T2>
674 void assert_same_type(const T2& t2) noexcept {
675 // in the second conditional test, make T2 const in case the user
676 // specifies a const T1 parameter type
677 static_assert(RelatedTest<T1, T2>::value && RelatedTest<const T2, T1>::value,
678 "Cgu::DoIf::assert_same_type() failed");
679 }
680
681 /**
682 * This function provides a compile time assertion that the static
683 * type of the arguments passed are related to each other (that is,
684 * either they are the same or one is publicly derived from the
685 * other). If they are not, a compile time error will occur (with a
686 * message that "Cgu::DoIf::assert_related_types() failed", and the
687 * line at which this function is reported as instantiated will be the
688 * line at which the assertion failed).
689 *
690 * For example "Cgu::DoIf::assert_related_types(a, b)" will fail to
691 * compile unless the static types of 'a' and 'b' are the same or one
692 * of the static types is publicly derived from the other. In making
693 * this test, constness is discarded and not taken into account: types
694 * can be related even if one is const and the other is not.
695 *
696 * See assert_related_to_type() for a test where the ordering of the
697 * arguments is significant, so that which of them must be the base
698 * type can be stated.
699 *
700 * This function can be viewed as doing the opposite of
701 * Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(): it causes a compilation
702 * error where the test is not met, rather than doing nothing.
703 * However, unlike those functions, as mentioned above
704 * assert_related_types() discards constness in making the test.
705 *
706 * It generates no object code, and is therefore thread safe and does
707 * not throw.
708 */
709 template <class T1, class T2>
710 void assert_related_types(const T1& t1, const T2& t2) noexcept {
711 static_assert(RelatedTest<T1, T2>::value || RelatedTest<T2, T1>::value,
712 "Cgu::DoIf::assert_related_types() failed");
713 }
714
715 /**
716 * This function provides a compile time assertion that the static
717 * type of the argument passed is not const. If it is, a compile time
718 * error will occur (with a message that
719 * "Cgu::DoIf::assert_not_const() failed", and the line at which this
720 * function is reported as instantiated will be the line at which the
721 * assertion failed).
722 *
723 * For example 'Cgu::DoIf::assert_not_const(a)' will fail to compile
724 * unless the static type of 'a' is not const.
725 *
726 * It generates no object code, and is therefore thread safe and does
727 * not throw.
728 *
729 * Since 2.0.1
730 */
731 template <class T>
732 void assert_not_const(T& t) noexcept {
733 static_assert(RelatedTest<typename std::remove_const<T>::type, T>::value,
734 "Cgu::DoIf::assert_not_const() failed");
735 }
736
737 #ifndef DOXYGEN_PARSING
738
739 /*
740 These classes and associated helper function employ 'RelatedTest' to
741 implement conditional compilation using templates and derivation.
742 They can be used with non-static class functions, static class
743 functions.
744 */
745 /*
746 the static member functions for the 'false' specialisations take
747 Args... rather just an elipsis argument so that any argument can be
748 a non-POD type
749 */
750
751 template <bool value, class Ret>
752 struct cond_call {};
753
754 /* cond_call implementation */
755
756 /* case of true with a return value */
757
758 template <class Ret>
759 struct cond_call<true, Ret> {
760 template <class T, class Func, class... Args>
761 static Ret exec(T& obj,
762 Func func,
763 Args&&... args) {
764 return (obj.*func)(std::forward<Args>(args)...);
765 }
766
767 template <class T, class Func, class... Args>
768 static Ret exec_static(T& obj,
769 Func func,
770 Args&&... args) {
771 return func(&obj, std::forward<Args>(args)...);
772 }
773 };
774
775 /* case of false with a return value */
776
777 template <class Ret>
778 struct cond_call<false, Ret> {
779 template <class T, class Func, class... Args>
780 static Ret exec(T&,
781 Func,
782 Args&&...) {
783 return Ret();
784 }
785
786 template <class T, class Func, class... Args>
787 static Ret exec_static(T&,
788 Func,
789 Args&&...) {
790 return Ret();
791 }
792 };
793
794 /* case of true with no return value */
795
796 template <>
797 struct cond_call<true, void> {
798 template <class T, class Func, class... Args>
799 static void exec(T& obj,
800 Func func,
801 Args&&... args) {
802 (obj.*func)(std::forward<Args>(args)...);
803 }
804
805 template <class T, class Func, class... Args>
806 static void exec_static(T& obj,
807 Func func,
808 Args&&... args) {
809 func(&obj, std::forward<Args>(args)...);
810 }
811 };
812
813 /* case of false with no return value */
814
815 template <>
816 struct cond_call<false, void> {
817 template <class T, class Func, class... Args>
818 static void exec(T&,
819 Func,
820 Args&&...) {}
821
822 template <class T, class Func, class... Args>
823 static void exec_static(T&,
824 Func,
825 Args&&...) {}
826 };
827
828 #endif /* DOXYGEN_PARSING */
829
830 /* the mem_fun() forwarding functions */
831
832 /* with return value */
833
834 /**
835 * This function overload conditionally executes the member function
836 * passed as the second argument if the class object passed as the
837 * first argument has it as a member (say by derivation), otherwise it
838 * does nothing. This function is thread safe if the referenced
839 * member function is thread safe. It does not throw unless the
840 * referenced member function throws or (if its arguments are not
841 * built-in types nor reference arguments) the copy constructor of one
842 * of the member function's arguments throws, or (if no call is made)
843 * the return type's default constructor throws.
844 * @return The result of the function call, or if no call is made, an
845 * empty object obtained by calling the return type's default
846 * constructor.
847 */
848 template <class Base, class Obj, class Ret, class... Params, class... Args>
849 Ret mem_fun(Obj& obj,
850 Ret (Base::*func)(Params...),
851 Args&&... args) {
852 return cond_call<RelatedTest<Base, Obj>::value, Ret>::exec(obj, func,
853 std::forward<Args>(args)...);
854 }
855
856 /* no return value */
857
858 /**
859 * This function overload conditionally executes the member function
860 * passed as the second argument if the class object passed as the
861 * first argument has it as a member (say by derivation), otherwise it
862 * does nothing. This function is thread safe if the referenced
863 * member function is thread safe. It does not throw unless the
864 * referenced member function throws or (if its arguments are not
865 * built-in types nor reference arguments) the copy constructor of one
866 * of the member function's arguments throws.
867 */
868 template <class Base, class Obj, class... Params, class... Args>
869 void mem_fun(Obj& obj,
870 void (Base::*func)(Params...),
871 Args&&... args) {
872 cond_call<RelatedTest<Base, Obj>::value, void>::exec(obj, func,
873 std::forward<Args>(args)...);
874 }
875
876 /* for const member functions */
877
878 /* with return value */
879
880 /**
881 * This function overload conditionally executes the member function
882 * passed as the second argument if the class object passed as the
883 * first argument has it as a member (say by derivation), otherwise it
884 * does nothing. This function is thread safe if the referenced
885 * member function is thread safe. It does not throw unless the
886 * referenced member function throws or (if its arguments are not
887 * built-in types nor reference arguments) the copy constructor of one
888 * of the member function's arguments throws, or (if no call is made)
889 * the return type's default constructor throws.
890 * @return The result of the function call, or if no call is made, an
891 * empty object obtained by calling the return type's default
892 * constructor.
893 */
894 template <class Base, class Obj, class Ret, class... Params, class... Args>
895 Ret mem_fun(const Obj& obj,
896 Ret (Base::*func)(Params...) const,
897 Args&&... args) {
898 return cond_call<RelatedTest<Base, Obj>::value, Ret>::exec(obj, func,
899 std::forward<Args>(args)...);
900 }
901
902 /* no return value */
903
904 /**
905 * This function overload conditionally executes the member function
906 * passed as the second argument if the class object passed as the
907 * first argument has it as a member (say by derivation), otherwise it
908 * does nothing. This function is thread safe if the referenced
909 * member function is thread safe. It does not throw unless the
910 * referenced member function throws or (if its arguments are not
911 * built-in types nor reference arguments) the copy constructor of one
912 * of the member function's arguments throws.
913 */
914 template <class Base, class Obj, class... Params, class... Args>
915 void mem_fun(const Obj& obj,
916 void (Base::*func)(Params...) const,
917 Args&&... args) {
918 cond_call<RelatedTest<Base, Obj>::value, void>::exec(obj, func,
919 std::forward<Args>(args)...);
920 }
921
922 /* for ordinary functions and static member functions */
923
924 /* with return value */
925 /**
926 * This function overload conditionally executes the function passed
927 * as the second argument if the object passed as the first argument
928 * relates to (ie is an instance of or derived from) the type to which
929 * the first argument of the function to be conditionally executed is
930 * a pointer, otherwise it does nothing. This function is thread safe
931 * if the referenced function to be called is thread safe. It does
932 * not throw unless the referenced function throws or (if its
933 * arguments are not built-in types nor reference arguments) the copy
934 * constructor of one of the referenced function's arguments throws,
935 * or (if no call is made) the return type's default constructor
936 * throws.
937 * @return The result of the function call, or if no call is made, an
938 * empty object obtained by calling the return type's default
939 * constructor.
940 */
941 template <class Base, class Obj, class Ret, class... Params, class... Args>
942 Ret fun(Obj& obj,
943 Ret (*func)(Base*, Params...),
944 Args&&... args) {
945 return cond_call<RelatedTest<Base, Obj>::value, Ret>::exec_static(obj, func,
946 std::forward<Args>(args)...);
947 }
948
949 /* no return value */
950
951 /**
952 * This function overload conditionally executes the function passed
953 * as the second argument if the object passed as the first argument
954 * relates to (ie is an instance of or derived from) the type to which
955 * the first argument of the function to be conditionally executed is
956 * a pointer, otherwise it does nothing. This function is thread safe
957 * if the referenced function to be called is thread safe. It does
958 * not throw unless the referenced function throws or (if its
959 * arguments are not built-in types nor reference arguments) the copy
960 * constructor of one of the referenced function's arguments throws.
961 */
962 template <class Base, class Obj, class... Params, class... Args>
963 void fun(Obj& obj,
964 void (*func)(Base*, Params...),
965 Args&&... args) {
966 cond_call<RelatedTest<Base, Obj>::value, void>::exec_static(obj, func,
967 std::forward<Args>(args)...);
968 }
969
970 } // namespace DoIf
971
972 } // namespace Cgu
973
974 #endif /* CGU_DO_IF */
Cgu
Definition: application.h:44
Cgu::DoIf::RelatedTest::value
static const bool value
Definition: do_if.h:562
Cgu::Extension::exec
auto exec(const std::string &preamble, const std::string &file, Translator &&translator) -> typename std::result_of< Translator(SCM)>::type
Definition: extension.h:1659
Cgu::DoIf::RelatedTest
Class for compile time testing of inheritance relationships.
Definition: do_if.h:538
Cgu::DoIf::assert_related_types
void assert_related_types(const T1 &t1, const T2 &t2) noexcept
Definition: do_if.h:710
Cgu::DoIf::assert_related_to_type
void assert_related_to_type(const Base &b, const Obj &o) noexcept
Definition: do_if.h:593
Cgu::DoIf::assert_not_const
void assert_not_const(T &t) noexcept
Definition: do_if.h:732
Cgu::DoIf::assert_same_type
void assert_same_type(const T1 &t1, const T2 &t2) noexcept
Definition: do_if.h:646
Cgu::DoIf::mem_fun
Ret mem_fun(Obj &obj, Ret(Base::*func)(Params...), Args &&... args)
Definition: do_if.h:849
cgu_config.h
Cgu::DoIf::fun
Ret fun(Obj &obj, Ret(*func)(Base *, Params...), Args &&... args)
Definition: do_if.h:942