c++-gtk-utils
|
00001 /* Copyright (C) 2010 and 2011 Chris Vine 00002 00003 The library comprised in this file or of which this file is part is 00004 distributed by Chris Vine under the GNU Lesser General Public 00005 License as follows: 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Lesser General Public License 00009 as published by the Free Software Foundation; either version 2.1 of 00010 the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, but 00013 WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Lesser General Public License, version 2.1, for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public 00018 License, version 2.1, along with this library (see the file LGPL.TXT 00019 which came with this source code package in the c++-gtk-utils 00020 sub-directory); if not, write to the Free Software Foundation, Inc., 00021 59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA. 00022 00023 However, it is not intended that the object code of a program whose 00024 source code instantiates a template from this file or uses macros or 00025 inline functions (of any length) should by reason only of that 00026 instantiation or use be subject to the restrictions of use in the GNU 00027 Lesser General Public License. With that in mind, the words "and 00028 macros, inline functions and instantiations of templates (of any 00029 length)" shall be treated as substituted for the words "and small 00030 macros and small inline functions (ten lines or less in length)" in 00031 the fourth paragraph of section 5 of that licence. This does not 00032 affect any other reason why object code may be subject to the 00033 restrictions in that licence (nor for the avoidance of doubt does it 00034 affect the application of section 2 of that licence to modifications 00035 of the source code in this file). 00036 00037 */ 00038 00039 #ifndef CGU_DO_IF_H 00040 #define CGU_DO_IF_H 00041 00042 /** 00043 * @file do_if.h 00044 * @brief This file provides utility functions for conditional compilation. 00045 * 00046 * \#include <c++-gtk-utils/do_if.h> 00047 * 00048 * The DoIf namespace of the library provides a small subset of 00049 * template meta-programming techniques likely to be most relevant to 00050 * GUI programming (if something more substantial is required, 00051 * something like boost or loki should be used). 00052 * 00053 * For conditional compilation, the library provides the 00054 * Cgu::DoIf::mem_fun() utility functions which will conditionally 00055 * compile a call to a non-static class member function if, and only 00056 * if, the target object has that function as a member. If it does 00057 * not have the member function as a member, the call will just do 00058 * nothing rather than generate a compiler error, as it will also if 00059 * the target object is const and the member function to be called is 00060 * non-const. In addition Cgu::DoIf::fun() will conditionally compile 00061 * a call to an ordinary function (or static member function) if, and 00062 * only if, the target object is convertible to the type (say, a base 00063 * type) held by pointer as the first argument of that function. 00064 * 00065 * They therefore provide compile-time inheritance checking based on 00066 * the static type of the object passed to them. They save dynamic 00067 * casting (and therefore run time overhead and the requirement for 00068 * target types to have a virtual method) in templated functions when 00069 * the static type is all that is necessary to enable type checking to 00070 * be carried out. 00071 * 00072 * This is not just a template curiosity, but enables more generic 00073 * programming practices when, say, passing mixins to templated 00074 * functions. A templated function can be passed an object as a 00075 * template type, and that function can then conditionally call member 00076 * functions of objects passed to it. If the object has a particular 00077 * function as a member, Cgu::DoIf::mem_fun() will call the function, 00078 * and if not it will do nothing without causing a compilation error. 00079 * It can be particularly useful for templated set-up or tear-down 00080 * functions intended to take a wide variety of different objects with 00081 * differing features. 00082 * 00083 * As mentioned above, Cgu::DoIf::mem_fun() and Cgu::DoIf::fun() will 00084 * do nothing if an attempt is made to execute a non-const function on 00085 * a const object, as well as if the object type does not match the 00086 * function or member function sought to be invoked. If a compilation 00087 * failure is wanted in a case of const mismatch instead of doing 00088 * nothing, from version 2.0.1 the static assertion 00089 * Cgu::DoIf::assert_not_const() can be invoked before the call to a 00090 * non-const function is made by Cgu::DoIf::mem_fun() or 00091 * Cgu::DoIf::fun(). 00092 * 00093 * @b Non-static @b member @b functions 00094 * 00095 * The first argument to be passed to Cgu::DoIf::mem_fun() is the 00096 * target object to be tested and the second argument is the 00097 * non-static member function which is to be called with respect to 00098 * that object if it has the function as a member. Any number of 00099 * further arguments can be passed, representing the arguments to be 00100 * provided to that member function. These further arguments may be 00101 * reference arguments (const or non-const), value arguments or 00102 * r-values, and for automatic pass-through they are passed by r-value 00103 * reference and std::forward(), so no overhead should be created if 00104 * value or r-value arguments are passed via Cgu::DoIf::mem_fun(). 00105 * 00106 * As an example, take a class which uses multiple inheritance to 00107 * inherit from Cgu::EmitterArg as a mixin (normally a class would 00108 * have an Emitter object as a member, but it can be inherited from). 00109 * A container of objects could have the emit() method called on them 00110 * in a case where they do inherit from EmitterArg, where the code 00111 * does nothing if they do not. For example: 00112 * @code 00113 * class Calc { 00114 * public: 00115 * void do_calc(void); 00116 * }; 00117 * 00118 * class CalcEmit: public Calc, 00119 * public Cgu::EmitterArg<int> { 00120 * }; 00121 * 00122 * ... some code blocks elsewhere ... 00123 * 00124 * template <class T> 00125 * void dispatch_calcs(const std::vector<T>& v) { 00126 * int count; 00127 * typename std::vector<T>::const_iterator iter; 00128 * for (count = 0, iter = v.begin(); 00129 * iter != v.end(); 00130 * ++count, ++iter) { 00131 * iter->do_calc(); 00132 * Cgu::DoIf::mem_fun(*iter, // object to be tested 00133 * &Cgu::EmitterArg<int>::emit, // member function to be conditionally called 00134 * count); // argument 00135 * } 00136 * } 00137 * @endcode 00138 * 00139 * @b Ordinary @b functions @b and @b static @b member @b functions 00140 * 00141 * The use of Cgu::DoIf::fun() with normal functions and static member 00142 * functions is similar to the use of mem_fun() with non-static member 00143 * functions, except that the first argument of the function to be 00144 * conditionally called must be a pointer to a type to which the 00145 * target object can prospectively be converted. The first argument 00146 * to be passed to Cgu::DoIf::fun() is the target object to be tested 00147 * and the second argument is the function which is to be 00148 * conditionally called if the conversion can be accomplished. If the 00149 * function to be conditionally called is so called, the target object 00150 * will be passed by pointer to it. Any number of further arguments 00151 * can be passed to Cgu::DoIf::fun(), representing additional 00152 * arguments to be provided to the function to be conditionally 00153 * called, which may be reference arguments, value arguments or 00154 * r-value reference arguments (and automatic pass-through is 00155 * provided, as in the case of mem_fun()). 00156 * 00157 * The use of Cgu::DoIf::fun() with ordinary functions can be useful 00158 * for batching a number of calls to be made to a test object. For 00159 * example: 00160 * 00161 * @code 00162 * class Calc { 00163 * public: 00164 * void do_calc(); 00165 * }; 00166 * 00167 * class CalcEmit: public Calc, 00168 * public Cgu::EmitterArg<int> { 00169 * public: 00170 * void clean_up(int); 00171 * }; 00172 * 00173 * ... some code blocks elsewhere ... 00174 * 00175 * void emit_on_calcs(CalcEmit* c, int count) { 00176 * c->emit(count); 00177 * c->clean_up(count); 00178 * } 00179 * 00180 * template <class T> 00181 * void dispatch_calcs(const std::vector<T>& v) { 00182 * int count; 00183 * typename std::vector<T>::const_iterator iter; 00184 * for (count = 0, iter = v.begin(); 00185 * iter != v.end(); 00186 * ++count, ++iter) { 00187 * iter->do_calc(); 00188 * Cgu::DoIf::fun(*iter, // object to be tested against first argument of function to be conditionally called 00189 * &emit_on_calcs, // function to be conditionally called 00190 * count); // second argument of function to be conditionally called 00191 * } 00192 * } 00193 * @endcode 00194 * 00195 * @b Return @b values 00196 * 00197 * If the function to be called returns something other than void and 00198 * the function to be conditionally called is not called, then 00199 * mem_fun() and fun() pass back a dummy object of the return type 00200 * using that type's default constructor. The returned object has no 00201 * meaning beyond that in such a case, so it should not be relied on 00202 * as holding anything other than its default value on default 00203 * construction in a case of failure. This in turn means that any 00204 * return value, if not a built-in type, must have a default 00205 * constructor. 00206 * 00207 * @b Overloaded @b functions 00208 * 00209 * Where a referenced member function or ordinary function is 00210 * overloaded, this will cause difficulties in template type deduction 00211 * when mem_fun() or fun() is called, requiring explicit 00212 * disambiguation. For example the following will fail to compile 00213 * unless explicitly disambiguated: 00214 * @code 00215 * class A { 00216 * public: 00217 * void do_it(int i); 00218 * void do_it(int i, int j); 00219 * void do_it(double d); 00220 * }; 00221 * int func(A* a, int i); 00222 * int func(A* a, double d); 00223 * 00224 * template <class T> 00225 * void do_it_if(T& t) { 00226 * int i = 1, j = 2; 00227 * double d = 10.0; 00228 * Cgu::DoIf::mem_fun(t, &A::do_it, i); // won't compile 00229 * Cgu::DoIf::mem_fun(t, &A::do_it, i, j); // won't compile 00230 * Cgu::DoIf::mem_fun(t, &A::do_it, d); // won't compile 00231 * Cgu::DoIf::fun(t, func, i); // won't compile 00232 * Cgu::DoIf::fun(t, func, d); // won't compile 00233 * 00234 * Cgu::DoIf::mem_fun(t, static_cast<void (A::*)(int)>(&A::do_it), i); // OK 00235 * Cgu::DoIf::mem_fun(t, static_cast<void (A::*)(int, int)>(&A::do_it), i, j); // OK 00236 * Cgu::DoIf::mem_fun(t, static_cast<void (A::*)(double)>(&A::do_it), d); // OK 00237 * Cgu::DoIf::fun(t, static_cast<int (*)(A*, int)>(func), i); // OK 00238 * Cgu::DoIf::fun(t, static_cast<int (*)(A*, double)>(func), d); // OK 00239 * } 00240 * @endcode 00241 * 00242 * @b Static @b assertion 00243 * 00244 * This library also provides the Cgu::DoIf::assert_related_to_type(), 00245 * Cgu::DoIf::assert_related_types() and Cgu::DoIf::assert_same_type() 00246 * static type-checking assertions. If the matters asserted are not 00247 * true, a compile time error in the line where the functions are 00248 * instantiated will occur. 00249 * 00250 * These static assertion functions can be viewed as doing the 00251 * opposite of Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(). The 00252 * mem_fun() and fun() functions will make a conditional call, and do 00253 * nothing if the test condition is not met without a compile time or 00254 * run time error, in order to provide compile time polymorphism. On 00255 * the other hand, assert_related_to_type(), assert_related_types() 00256 * and assert_same_type() cause an explicit compilation error where 00257 * the test condition is not met at an ascertainable point in the code 00258 * whilst avoiding a slew of incomprehensible error messages from the 00259 * compiler. They enable compile time checking of type related 00260 * invariants. 00261 * 00262 * In addition, from version 2.0.1, a Cgu::DoIf::assert_not_const() 00263 * static assertion is available. 00264 * 00265 * The static assertions add nothing to the compiled object code. 00266 * They either succeed or fail at compile time. 00267 */ 00268 00269 /** 00270 * @namespace Cgu::DoIf 00271 * @brief This namespace provides utility functions for conditional compilation. 00272 * 00273 * \#include <c++-gtk-utils/do_if.h> 00274 * 00275 * The DoIf namespace of the library provides a small subset of 00276 * template meta-programming techniques likely to be most relevant to 00277 * GUI programming (if something more substantial is required, 00278 * something like boost or loki should be used). 00279 * 00280 * For conditional compilation, the library provides the 00281 * Cgu::DoIf::mem_fun() utility functions which will conditionally 00282 * compile a call to a non-static class member function if, and only 00283 * if, the target object has that function as a member. If it does 00284 * not have the member function as a member, the call will just do 00285 * nothing rather than generate a compiler error, as it will also if 00286 * the target object is const and the member function to be called is 00287 * non-const. In addition Cgu::DoIf::fun() will conditionally compile 00288 * a call to an ordinary function (or static member function) if, and 00289 * only if, the target object is convertible to the type (say, a base 00290 * type) held by pointer as the first argument of that function. 00291 * 00292 * They therefore provide compile-time inheritance checking based on 00293 * the static type of the object passed to them. They save dynamic 00294 * casting (and therefore run time overhead and the requirement for 00295 * target types to have a virtual method) in templated functions when 00296 * the static type is all that is necessary to enable type checking to 00297 * be carried out. 00298 * 00299 * This is not just a template curiosity, but enables more generic 00300 * programming practices when, say, passing mixins to templated 00301 * functions. A templated function can be passed an object as a 00302 * template type, and that function can then conditionally call member 00303 * functions of objects passed to it. If the object has a particular 00304 * function as a member, Cgu::DoIf::mem_fun() will call the function, 00305 * and if not it will do nothing without causing a compilation error. 00306 * It can be particularly useful for templated set-up or tear-down 00307 * functions intended to take a wide variety of different objects with 00308 * differing features. 00309 * 00310 * As mentioned above, Cgu::DoIf::mem_fun() and Cgu::DoIf::fun() will 00311 * do nothing if an attempt is made to execute a non-const function on 00312 * a const object, as well as if the object type does not match the 00313 * function or member function sought to be invoked. If a compilation 00314 * failure is wanted in a case of const mismatch instead of doing 00315 * nothing, from version 2.0.1 the static assertion 00316 * Cgu::DoIf::assert_not_const() can be invoked before the call to a 00317 * non-const function is made by Cgu::DoIf::mem_fun() or 00318 * Cgu::DoIf::fun(). 00319 * 00320 * @b Non-static @b member @b functions 00321 * 00322 * The first argument to be passed to Cgu::DoIf::mem_fun() is the 00323 * target object to be tested and the second argument is the 00324 * non-static member function which is to be called with respect to 00325 * that object if it has the function as a member. Any number of 00326 * further arguments can be passed, representing the arguments to be 00327 * provided to that member function. These further arguments may be 00328 * reference arguments (const or non-const), value arguments or 00329 * r-values, and for automatic pass-through they are passed by r-value 00330 * reference and std::forward(), so no overhead should be created if 00331 * value or r-value arguments are passed via Cgu::DoIf::mem_fun(). 00332 * 00333 * As an example, take a class which uses multiple inheritance to 00334 * inherit from Cgu::EmitterArg as a mixin (normally a class would 00335 * have an Emitter object as a member, but it can be inherited from). 00336 * A container of objects could have the emit() method called on them 00337 * in a case where they do inherit from EmitterArg, where the code 00338 * does nothing if they do not. For example: 00339 * @code 00340 * class Calc { 00341 * public: 00342 * void do_calc(void); 00343 * }; 00344 * 00345 * class CalcEmit: public Calc, 00346 * public Cgu::EmitterArg<int> { 00347 * }; 00348 * 00349 * ... some code blocks elsewhere ... 00350 * 00351 * template <class T> 00352 * void dispatch_calcs(const std::vector<T>& v) { 00353 * int count; 00354 * typename std::vector<T>::const_iterator iter; 00355 * for (count = 0, iter = v.begin(); 00356 * iter != v.end(); 00357 * ++count, ++iter) { 00358 * iter->do_calc(); 00359 * Cgu::DoIf::mem_fun(*iter, // object to be tested 00360 * &Cgu::EmitterArg<int>::emit, // member function to be conditionally called 00361 * count); // argument 00362 * } 00363 * } 00364 * @endcode 00365 * 00366 * @b Ordinary @b functions @b and @b static @b member @b functions 00367 * 00368 * The use of Cgu::DoIf::fun() with normal functions and static member 00369 * functions is similar to the use of mem_fun() with non-static member 00370 * functions, except that the first argument of the function to be 00371 * conditionally called must be a pointer to a type to which the 00372 * target object can prospectively be converted. The first argument 00373 * to be passed to Cgu::DoIf::fun() is the target object to be tested 00374 * and the second argument is the function which is to be 00375 * conditionally called if the conversion can be accomplished. If the 00376 * function to be conditionally called is so called, the target object 00377 * will be passed by pointer to it. Any number of further arguments 00378 * can be passed to Cgu::DoIf::fun(), representing additional 00379 * arguments to be provided to the function to be conditionally 00380 * called, which may be reference arguments, value arguments or 00381 * r-value reference arguments (and automatic pass-through is 00382 * provided, as in the case of mem_fun()). 00383 * 00384 * The use of Cgu::DoIf::fun() with ordinary functions can be useful 00385 * for batching a number of calls to be made to a test object. For 00386 * example: 00387 * 00388 * @code 00389 * class Calc { 00390 * public: 00391 * void do_calc(); 00392 * }; 00393 * 00394 * class CalcEmit: public Calc, 00395 * public Cgu::EmitterArg<int> { 00396 * public: 00397 * void clean_up(int); 00398 * }; 00399 * 00400 * ... some code blocks elsewhere ... 00401 * 00402 * void emit_on_calcs(CalcEmit* c, int count) { 00403 * c->emit(count); 00404 * c->clean_up(count); 00405 * } 00406 * 00407 * template <class T> 00408 * void dispatch_calcs(const std::vector<T>& v) { 00409 * int count; 00410 * typename std::vector<T>::const_iterator iter; 00411 * for (count = 0, iter = v.begin(); 00412 * iter != v.end(); 00413 * ++count, ++iter) { 00414 * iter->do_calc(); 00415 * Cgu::DoIf::fun(*iter, // object to be tested against first argument of function to be conditionally called 00416 * &emit_on_calcs, // function to be conditionally called 00417 * count); // second argument of function to be conditionally called 00418 * } 00419 * } 00420 * @endcode 00421 * 00422 * @b Return @b values 00423 * 00424 * If the function to be called returns something other than void and 00425 * the function to be conditionally called is not called, then 00426 * mem_fun() and fun() pass back a dummy object of the return type 00427 * using that type's default constructor. The returned object has no 00428 * meaning beyond that in such a case, so it should not be relied on 00429 * as holding anything other than its default value on default 00430 * construction in a case of failure. This in turn means that any 00431 * return value, if not a built-in type, must have a default 00432 * constructor. 00433 * 00434 * @b Overloaded @b functions 00435 * 00436 * Where a referenced member function or ordinary function is 00437 * overloaded, this will cause difficulties in template type deduction 00438 * when mem_fun() or fun() is called, requiring explicit 00439 * disambiguation. For example the following will fail to compile 00440 * unless explicitly disambiguated: 00441 * @code 00442 * class A { 00443 * public: 00444 * void do_it(int i); 00445 * void do_it(int i, int j); 00446 * void do_it(double d); 00447 * }; 00448 * int func(A* a, int i); 00449 * int func(A* a, double d); 00450 * 00451 * template <class T> 00452 * void do_it_if(T& t) { 00453 * int i = 1, j = 2; 00454 * double d = 10.0; 00455 * Cgu::DoIf::mem_fun(t, &A::do_it, i); // won't compile 00456 * Cgu::DoIf::mem_fun(t, &A::do_it, i, j); // won't compile 00457 * Cgu::DoIf::mem_fun(t, &A::do_it, d); // won't compile 00458 * Cgu::DoIf::fun(t, func, i); // won't compile 00459 * Cgu::DoIf::fun(t, func, d); // won't compile 00460 * 00461 * Cgu::DoIf::mem_fun(t, static_cast<void (A::*)(int)>(&A::do_it), i); // OK 00462 * Cgu::DoIf::mem_fun(t, static_cast<void (A::*)(int, int)>(&A::do_it), i, j); // OK 00463 * Cgu::DoIf::mem_fun(t, static_cast<void (A::*)(double)>(&A::do_it), d); // OK 00464 * Cgu::DoIf::fun(t, static_cast<int (*)(A*, int)>(func), i); // OK 00465 * Cgu::DoIf::fun(t, static_cast<int (*)(A*, double)>(func), d); // OK 00466 * } 00467 * @endcode 00468 * 00469 * @b Static @b assertion 00470 * 00471 * This library also provides the Cgu::DoIf::assert_related_to_type(), 00472 * Cgu::DoIf::assert_related_types() and Cgu::DoIf::assert_same_type() 00473 * static type-checking assertions. If the matters asserted are not 00474 * true, a compile time error in the line where the functions are 00475 * instantiated will occur. 00476 * 00477 * These static assertion functions can be viewed as doing the 00478 * opposite of Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(). The 00479 * mem_fun() and fun() functions will make a conditional call, and do 00480 * nothing if the test condition is not met without a compile time or 00481 * run time error, in order to provide compile time polymorphism. On 00482 * the other hand, assert_related_to_type(), assert_related_types() 00483 * and assert_same_type() cause an explicit compilation error where 00484 * the test condition is not met at an ascertainable point in the code 00485 * whilst avoiding a slew of incomprehensible error messages from the 00486 * compiler. They enable compile time checking of type related 00487 * invariants. 00488 * 00489 * In addition, from version 2.0.1, a Cgu::DoIf::assert_not_const() 00490 * static assertion is available. 00491 * 00492 * The static assertions add nothing to the compiled object code. 00493 * They either succeed or fail at compile time. 00494 */ 00495 00496 #include <utility> // for std::forward 00497 #include <type_traits> // for std::true_type, std::false_type and std::remove_const 00498 00499 #include <c++-gtk-utils/cgu_config.h> 00500 00501 namespace Cgu { 00502 00503 namespace DoIf { 00504 00505 /** 00506 * @class RelatedTest do_if.h c++-gtk-utils/do_if.h 00507 * @brief Class for compile time testing of inheritance relationships 00508 * @sa mem_fun fun 00509 * 00510 * This class provides a compile time test of whether the Obj class 00511 * template parameter type is related to the Base class template 00512 * parameter type by public derivation, or they are of the same type: 00513 * the 'value' public member will be true if they are, otherwise 00514 * false. Everything in it comprises a compile time constant so that 00515 * 'value' can be used as a template parameter for conditional 00516 * complation. Because 'RelatedTest' has a static member named 00517 * 'value', it can also be used with boost's 'enable_if' templates. 00518 * 00519 * This class tests convertibility, and constness is not discarded in 00520 * making the test. Whilst a non-const type passed as the second 00521 * template parameter will (if the other conditions referred to above 00522 * are met) be shown as related to a const base type or const same 00523 * type specified as the first template parameter type, the reverse is 00524 * not true. This ensures that the DoIf::mem_fun() and DoIf::fun() 00525 * conditional compilation functions work correctly. 00526 */ 00527 00528 template<class Base, class Obj> 00529 class RelatedTest { 00530 00531 static std::true_type test(Base*); 00532 static std::false_type test(...); 00533 00534 typedef decltype(test(static_cast<Obj*>(0))) TestObjType; 00535 typedef decltype(test(static_cast<void*>(0))) TestVoidType; 00536 00537 public: 00538 /** 00539 * A compile time constant which indicates whether the Obj class 00540 * template parameter type is related to the Base class template 00541 * parameter type by public derivation, or they are of the same type. 00542 * Because it is a compile time constant it can be used as a template 00543 * parameter and therefore for conditional compilation. 00544 * 00545 * This constant specifies convertibility, and constness is not 00546 * discarded in making the test. Whilst a non-const type passed as 00547 * the second template parameter will (if the other conditions 00548 * referred to above are met) be shown as related to a const base type 00549 * or const same type specified as the first template parameter type, 00550 * the reverse is not true. This ensures that the DoIf::mem_fun() and 00551 * DoIf::fun() conditional compilation functions work correctly. 00552 */ 00553 static const bool value = TestObjType::value == true 00554 && TestVoidType::value == false; 00555 }; 00556 00557 /** 00558 * This function provides a compile time assertion that the static 00559 * type of the second argument passed to it is related to (that is, 00560 * either the same as or publicly derived from) the static type of the 00561 * first argument. If it is not, a compile time error will occur 00562 * (with a message that "Cgu::DoIf::assert_related_to_type() failed", 00563 * and the line at which this function is reported as instantiated 00564 * will be the line at which the assertion failed). 00565 * 00566 * For example "Cgu::DoIf::assert_related_to_type(a, b)" will fail to 00567 * compile unless the static type of 'b' is the same as or publicly 00568 * derived from the static type of 'a'. In making this test, 00569 * constness is discarded and not taken into account. 00570 * 00571 * See assert_related_types() for a test where the ordering of the 00572 * arguments is not significant. 00573 * 00574 * This function can be viewed as doing the opposite of 00575 * Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(): it causes a compilation 00576 * error where the test is not met, rather than doing nothing. 00577 * However, unlike those functions, as mentioned above 00578 * assert_related_to_type() discards constness in making the test. 00579 * 00580 * It generates no object code, and is therefore thread safe and does 00581 * not throw. 00582 */ 00583 template <class Base, class Obj> 00584 void assert_related_to_type(const Base& b, const Obj& o) { 00585 static_assert(RelatedTest<Base, Obj>::value, 00586 "Cgu::DoIf::assert_related_to_type() failed"); 00587 } 00588 00589 /** 00590 * This function provides a compile time assertion that the static 00591 * type of the argument passed to it is related to (that is, either 00592 * the same as or publicly derived from) the type given as the 00593 * explicit template parameter to the function call. If it is not, a 00594 * compile time error will occur (with a message that 00595 * "Cgu::DoIf::assert_related_to_type() failed", and the line at which 00596 * this function is reported as instantiated will be the line at which 00597 * the assertion failed). 00598 * 00599 * For example "Cgu::DoIf::assert_related_to_type<A>(x)" will fail to 00600 * compile unless the static type of 'x' is the same as or publicly 00601 * derived from type A. In making this test, constness is discarded 00602 * and not taken into account. 00603 * 00604 * This function can be viewed as doing the opposite of 00605 * Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(): it causes a compilation 00606 * error where the test is not met, rather than doing nothing. 00607 * However, unlike those functions, as mentioned above 00608 * assert_related_to_type() discards constness in making the test. 00609 * 00610 * It generates no object code, and is therefore thread safe and does 00611 * not throw. 00612 */ 00613 template <class Base, class Obj> 00614 void assert_related_to_type(const Obj& o) { 00615 static_assert(RelatedTest<Base, Obj>::value, 00616 "Cgu::DoIf::assert_related_to_type() failed"); 00617 } 00618 00619 /** 00620 * This function provides a compile time assertion that the static 00621 * type of the first argument passed to it is the same as the static 00622 * type of the second argument. If it is not, a compile time error 00623 * will occur (with a message that "Cgu::DoIf::assert_same_type() 00624 * failed", and the line at which this function is reported as 00625 * instantiated will be the line at which the assertion failed). 00626 * 00627 * For example "Cgu::DoIf::assert_same_type(a, b)" will fail to 00628 * compile unless the static types of 'a' and 'b' are the same. In 00629 * making this test, constness is discarded and not taken into 00630 * account: types can be the same even if one is const and the other 00631 * is not. 00632 * 00633 * It generates no object code, and is therefore thread safe and does 00634 * not throw. 00635 */ 00636 template <class T1, class T2> 00637 void assert_same_type(const T1& t1, const T2& t2) { 00638 static_assert(RelatedTest<T1, T2>::value && RelatedTest<T2, T1>::value, 00639 "Cgu::DoIf::assert_same_type() failed"); 00640 } 00641 00642 /** 00643 * This function provides a compile time assertion that the static 00644 * type of the argument passed to it is the same as the type given as 00645 * the explicit template parameter to the function call. If it is 00646 * not, a compile time error will occur (with a message that 00647 * "Cgu::DoIf::assert_same_type() failed", and the line at which this 00648 * function is reported as instantiated will be the line at which the 00649 * assertion failed). 00650 * 00651 * For example "Cgu::DoIf::assert_same_type<A>(x)" will fail to 00652 * compile unless the static type of 'x' is type A. In making this 00653 * test, constness is discarded and not taken into account: types can 00654 * be the same even if one is const and the other is not. 00655 * 00656 * It generates no object code, and is therefore thread safe and does 00657 * not throw. 00658 * 00659 * Earlier versions of this function had a bug. A const type could 00660 * not be specified as the explicit template argument 00661 * (Cgu::DoIf::assert_same_type<const A>(x) would not work). This was 00662 * fixed in version 2.0.1. 00663 */ 00664 template <class T1, class T2> 00665 void assert_same_type(const T2& t2) { 00666 // in the second conditional test, make T2 const in case the user 00667 // specifies a const T1 parameter type 00668 static_assert(RelatedTest<T1, T2>::value && RelatedTest<const T2, T1>::value, 00669 "Cgu::DoIf::assert_same_type() failed"); 00670 } 00671 00672 /** 00673 * This function provides a compile time assertion that the static 00674 * type of the arguments passed are related to each other (that is, 00675 * either they are the same or one is publicly derived from the 00676 * other). If they are not, a compile time error will occur (with a 00677 * message that "Cgu::DoIf::assert_related_types() failed", and the 00678 * line at which this function is reported as instantiated will be the 00679 * line at which the assertion failed). 00680 * 00681 * For example "Cgu::DoIf::assert_related_types(a, b)" will fail to 00682 * compile unless the static types of 'a' and 'b' are the same or one 00683 * of the static types is publicly derived from the other. In making 00684 * this test, constness is discarded and not taken into account: types 00685 * can be related even if one is const and the other is not. 00686 * 00687 * See assert_related_to_type() for a test where the ordering of the 00688 * arguments is significant, so that which of them must be the base 00689 * type can be stated. 00690 * 00691 * This function can be viewed as doing the opposite of 00692 * Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(): it causes a compilation 00693 * error where the test is not met, rather than doing nothing. 00694 * However, unlike those functions, as mentioned above 00695 * assert_related_types() discards constness in making the test. 00696 * 00697 * It generates no object code, and is therefore thread safe and does 00698 * not throw. 00699 */ 00700 template <class T1, class T2> 00701 void assert_related_types(const T1& t1, const T2& t2) { 00702 static_assert(RelatedTest<T1, T2>::value || RelatedTest<T2, T1>::value, 00703 "Cgu::DoIf::assert_related_types() failed"); 00704 } 00705 00706 /** 00707 * This function provides a compile time assertion that the static 00708 * type of the argument passed is not const. If it is, a compile time 00709 * error will occur (with a message that 00710 * "Cgu::DoIf::assert_not_const() failed", and the line at which this 00711 * function is reported as instantiated will be the line at which the 00712 * assertion failed). 00713 * 00714 * For example 'Cgu::DoIf::assert_not_const(a)' will fail to compile 00715 * unless the static type of 'a' is not const. 00716 * 00717 * It generates no object code, and is therefore thread safe and does 00718 * not throw. 00719 * 00720 * Since 2.0.1 00721 */ 00722 template <class T> 00723 void assert_not_const(T& t) { 00724 static_assert(RelatedTest<typename std::remove_const<T>::type, T>::value, 00725 "Cgu::DoIf::assert_not_const() failed"); 00726 } 00727 00728 #ifndef DOXYGEN_PARSING 00729 00730 /* 00731 These classes and associated helper function employ 'RelatedTest' to 00732 implement conditional compilation using templates and derivation. 00733 They can be used with non-static class functions, static class 00734 functions. 00735 */ 00736 /* 00737 the static member functions for the 'false' specialisations take 00738 Args... rather just an elipsis argument so that any argument can be 00739 a non-POD type 00740 */ 00741 00742 template <bool value, class Ret> 00743 struct cond_call {}; 00744 00745 /* cond_call implementation */ 00746 00747 /* case of true with a return value */ 00748 00749 template <class Ret> 00750 struct cond_call<true, Ret> { 00751 template <class T, class Func, class... Args> 00752 static Ret exec(T& obj, 00753 Func func, 00754 Args&&... args) { 00755 return (obj.*func)(std::forward<Args>(args)...); 00756 } 00757 00758 template <class T, class Func, class... Args> 00759 static Ret exec_static(T& obj, 00760 Func func, 00761 Args&&... args) { 00762 return func(&obj, std::forward<Args>(args)...); 00763 } 00764 }; 00765 00766 /* case of false with a return value */ 00767 00768 template <class Ret> 00769 struct cond_call<false, Ret> { 00770 template <class T, class Func, class... Args> 00771 static Ret exec(T&, 00772 Func, 00773 Args&&...) { 00774 return Ret(); 00775 } 00776 00777 template <class T, class Func, class... Args> 00778 static Ret exec_static(T&, 00779 Func, 00780 Args&&...) { 00781 return Ret(); 00782 } 00783 }; 00784 00785 /* case of true with no return value */ 00786 00787 template <> 00788 struct cond_call<true, void> { 00789 template <class T, class Func, class... Args> 00790 static void exec(T& obj, 00791 Func func, 00792 Args&&... args) { 00793 (obj.*func)(std::forward<Args>(args)...); 00794 } 00795 00796 template <class T, class Func, class... Args> 00797 static void exec_static(T& obj, 00798 Func func, 00799 Args&&... args) { 00800 func(&obj, std::forward<Args>(args)...); 00801 } 00802 }; 00803 00804 /* case of false with no return value */ 00805 00806 template <> 00807 struct cond_call<false, void> { 00808 template <class T, class Func, class... Args> 00809 static void exec(T&, 00810 Func, 00811 Args&&...) {} 00812 00813 template <class T, class Func, class... Args> 00814 static void exec_static(T&, 00815 Func, 00816 Args&&...) {} 00817 }; 00818 00819 #endif /* DOXYGEN_PARSING */ 00820 00821 /* the mem_fun() forwarding functions */ 00822 00823 /* with return value */ 00824 00825 /** 00826 * This function overload conditionally executes the member function 00827 * passed as the second argument if the class object passed as the 00828 * first argument has it as a member (say by derivation), otherwise it 00829 * does nothing. This function is thread safe if the referenced 00830 * member function is thread safe. It does not throw unless the 00831 * referenced member function throws or (if its arguments are not 00832 * built-in types nor reference arguments) the copy constructor of one 00833 * of the member function's arguments throws, or (if no call is made) 00834 * the return type's default constructor throws. 00835 * @return The result of the function call, or if no call is made, an 00836 * empty object obtained by calling the return type's default 00837 * constructor. 00838 */ 00839 template <class Base, class Obj, class Ret, class... Params, class... Args> 00840 Ret mem_fun(Obj& obj, 00841 Ret (Base::*func)(Params...), 00842 Args&&... args) { 00843 return cond_call<RelatedTest<Base, Obj>::value, Ret>::exec(obj, func, 00844 std::forward<Args>(args)...); 00845 } 00846 00847 /* no return value */ 00848 00849 /** 00850 * This function overload conditionally executes the member function 00851 * passed as the second argument if the class object passed as the 00852 * first argument has it as a member (say by derivation), otherwise it 00853 * does nothing. This function is thread safe if the referenced 00854 * member function is thread safe. It does not throw unless the 00855 * referenced member function throws or (if its arguments are not 00856 * built-in types nor reference arguments) the copy constructor of one 00857 * of the member function's arguments throws. 00858 */ 00859 template <class Base, class Obj, class... Params, class... Args> 00860 void mem_fun(Obj& obj, 00861 void (Base::*func)(Params...), 00862 Args&&... args) { 00863 cond_call<RelatedTest<Base, Obj>::value, void>::exec(obj, func, 00864 std::forward<Args>(args)...); 00865 } 00866 00867 /* for const member functions */ 00868 00869 /* with return value */ 00870 00871 /** 00872 * This function overload conditionally executes the member function 00873 * passed as the second argument if the class object passed as the 00874 * first argument has it as a member (say by derivation), otherwise it 00875 * does nothing. This function is thread safe if the referenced 00876 * member function is thread safe. It does not throw unless the 00877 * referenced member function throws or (if its arguments are not 00878 * built-in types nor reference arguments) the copy constructor of one 00879 * of the member function's arguments throws, or (if no call is made) 00880 * the return type's default constructor throws. 00881 * @return The result of the function call, or if no call is made, an 00882 * empty object obtained by calling the return type's default 00883 * constructor. 00884 */ 00885 template <class Base, class Obj, class Ret, class... Params, class... Args> 00886 Ret mem_fun(const Obj& obj, 00887 Ret (Base::*func)(Params...) const, 00888 Args&&... args) { 00889 return cond_call<RelatedTest<Base, Obj>::value, Ret>::exec(obj, func, 00890 std::forward<Args>(args)...); 00891 } 00892 00893 /* no return value */ 00894 00895 /** 00896 * This function overload conditionally executes the member function 00897 * passed as the second argument if the class object passed as the 00898 * first argument has it as a member (say by derivation), otherwise it 00899 * does nothing. This function is thread safe if the referenced 00900 * member function is thread safe. It does not throw unless the 00901 * referenced member function throws or (if its arguments are not 00902 * built-in types nor reference arguments) the copy constructor of one 00903 * of the member function's arguments throws. 00904 */ 00905 template <class Base, class Obj, class... Params, class... Args> 00906 void mem_fun(const Obj& obj, 00907 void (Base::*func)(Params...) const, 00908 Args&&... args) { 00909 cond_call<RelatedTest<Base, Obj>::value, void>::exec(obj, func, 00910 std::forward<Args>(args)...); 00911 } 00912 00913 /* for ordinary functions and static member functions */ 00914 00915 /* with return value */ 00916 /** 00917 * This function overload conditionally executes the function passed 00918 * as the second argument if the object passed as the first argument 00919 * relates to (ie is an instance of or derived from) the type to which 00920 * the first argument of the function to be conditionally executed is 00921 * a pointer, otherwise it does nothing. This function is thread safe 00922 * if the referenced function to be called is thread safe. It does 00923 * not throw unless the referenced function throws or (if its 00924 * arguments are not built-in types nor reference arguments) the copy 00925 * constructor of one of the referenced function's arguments throws, 00926 * or (if no call is made) the return type's default constructor 00927 * throws. 00928 * @return The result of the function call, or if no call is made, an 00929 * empty object obtained by calling the return type's default 00930 * constructor. 00931 */ 00932 template <class Base, class Obj, class Ret, class... Params, class... Args> 00933 Ret fun(Obj& obj, 00934 Ret (*func)(Base*, Params...), 00935 Args&&... args) { 00936 return cond_call<RelatedTest<Base, Obj>::value, Ret>::exec_static(obj, func, 00937 std::forward<Args>(args)...); 00938 } 00939 00940 /* no return value */ 00941 00942 /** 00943 * This function overload conditionally executes the function passed 00944 * as the second argument if the object passed as the first argument 00945 * relates to (ie is an instance of or derived from) the type to which 00946 * the first argument of the function to be conditionally executed is 00947 * a pointer, otherwise it does nothing. This function is thread safe 00948 * if the referenced function to be called is thread safe. It does 00949 * not throw unless the referenced function throws or (if its 00950 * arguments are not built-in types nor reference arguments) the copy 00951 * constructor of one of the referenced function's arguments throws. 00952 */ 00953 template <class Base, class Obj, class... Params, class... Args> 00954 void fun(Obj& obj, 00955 void (*func)(Base*, Params...), 00956 Args&&... args) { 00957 cond_call<RelatedTest<Base, Obj>::value, void>::exec_static(obj, func, 00958 std::forward<Args>(args)...); 00959 } 00960 00961 } // namespace DoIf 00962 00963 } // namespace Cgu 00964 00965 #endif /* CGU_DO_IF */