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 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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, and can also be used with the std::enable_if template. 00517 * 00518 * This class tests convertibility, and constness is not discarded in 00519 * making the test. Whilst a non-const type passed as the second 00520 * template parameter will (if the other conditions referred to above 00521 * are met) be shown as related to a const base type or const same 00522 * type specified as the first template parameter type, the reverse is 00523 * not true. This ensures that the DoIf::mem_fun() and DoIf::fun() 00524 * conditional compilation functions work correctly. 00525 */ 00526 00527 template<class Base, class Obj> 00528 class RelatedTest { 00529 00530 static std::true_type test(Base*); 00531 static std::false_type test(...); 00532 00533 typedef decltype(test(static_cast<Obj*>(0))) TestObjType; 00534 typedef decltype(test(static_cast<void*>(0))) TestVoidType; 00535 00536 public: 00537 /** 00538 * A compile time constant which indicates whether the Obj class 00539 * template parameter type is related to the Base class template 00540 * parameter type by public derivation, or they are of the same type. 00541 * Because it is a compile time constant it can be used as a template 00542 * parameter and therefore for conditional compilation. 00543 * 00544 * This constant specifies convertibility, and constness is not 00545 * discarded in making the test. Whilst a non-const type passed as 00546 * the second template parameter will (if the other conditions 00547 * referred to above are met) be shown as related to a const base type 00548 * or const same type specified as the first template parameter type, 00549 * the reverse is not true. This ensures that the DoIf::mem_fun() and 00550 * DoIf::fun() conditional compilation functions work correctly. 00551 */ 00552 static const bool value = TestObjType::value == true 00553 && TestVoidType::value == false; 00554 }; 00555 00556 /** 00557 * This function provides a compile time assertion that the static 00558 * type of the second argument passed to it is related to (that is, 00559 * either the same as or publicly derived from) the static type of the 00560 * first argument. If it is not, a compile time error will occur 00561 * (with a message that "Cgu::DoIf::assert_related_to_type() failed", 00562 * and the line at which this function is reported as instantiated 00563 * will be the line at which the assertion failed). 00564 * 00565 * For example "Cgu::DoIf::assert_related_to_type(a, b)" will fail to 00566 * compile unless the static type of 'b' is the same as or publicly 00567 * derived from the static type of 'a'. In making this test, 00568 * constness is discarded and not taken into account. 00569 * 00570 * See assert_related_types() for a test where the ordering of the 00571 * arguments is not significant. 00572 * 00573 * This function can be viewed as doing the opposite of 00574 * Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(): it causes a compilation 00575 * error where the test is not met, rather than doing nothing. 00576 * However, unlike those functions, as mentioned above 00577 * assert_related_to_type() discards constness in making the test. 00578 * 00579 * It generates no object code, and is therefore thread safe and does 00580 * not throw. 00581 */ 00582 template <class Base, class Obj> 00583 void assert_related_to_type(const Base& b, const Obj& o) { 00584 static_assert(RelatedTest<Base, Obj>::value, 00585 "Cgu::DoIf::assert_related_to_type() failed"); 00586 } 00587 00588 /** 00589 * This function provides a compile time assertion that the static 00590 * type of the argument passed to it is related to (that is, either 00591 * the same as or publicly derived from) the type given as the 00592 * explicit template parameter to the function call. If it is not, a 00593 * compile time error will occur (with a message that 00594 * "Cgu::DoIf::assert_related_to_type() failed", and the line at which 00595 * this function is reported as instantiated will be the line at which 00596 * the assertion failed). 00597 * 00598 * For example "Cgu::DoIf::assert_related_to_type<A>(x)" will fail to 00599 * compile unless the static type of 'x' is the same as or publicly 00600 * derived from type A. In making this test, constness is discarded 00601 * and not taken into account. 00602 * 00603 * This function can be viewed as doing the opposite of 00604 * Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(): it causes a compilation 00605 * error where the test is not met, rather than doing nothing. 00606 * However, unlike those functions, as mentioned above 00607 * assert_related_to_type() discards constness in making the test. 00608 * 00609 * It generates no object code, and is therefore thread safe and does 00610 * not throw. 00611 */ 00612 template <class Base, class Obj> 00613 void assert_related_to_type(const Obj& o) { 00614 static_assert(RelatedTest<Base, Obj>::value, 00615 "Cgu::DoIf::assert_related_to_type() failed"); 00616 } 00617 00618 /** 00619 * This function provides a compile time assertion that the static 00620 * type of the first argument passed to it is the same as the static 00621 * type of the second argument. If it is not, a compile time error 00622 * will occur (with a message that "Cgu::DoIf::assert_same_type() 00623 * failed", and the line at which this function is reported as 00624 * instantiated will be the line at which the assertion failed). 00625 * 00626 * For example "Cgu::DoIf::assert_same_type(a, b)" will fail to 00627 * compile unless the static types of 'a' and 'b' are the same. In 00628 * making this test, constness is discarded and not taken into 00629 * account: types can be the same even if one is const and the other 00630 * is not. 00631 * 00632 * It generates no object code, and is therefore thread safe and does 00633 * not throw. 00634 */ 00635 template <class T1, class T2> 00636 void assert_same_type(const T1& t1, const T2& t2) { 00637 static_assert(RelatedTest<T1, T2>::value && RelatedTest<T2, T1>::value, 00638 "Cgu::DoIf::assert_same_type() failed"); 00639 } 00640 00641 /** 00642 * This function provides a compile time assertion that the static 00643 * type of the argument passed to it is the same as the type given as 00644 * the explicit template parameter to the function call. If it is 00645 * not, a compile time error will occur (with a message that 00646 * "Cgu::DoIf::assert_same_type() failed", and the line at which this 00647 * function is reported as instantiated will be the line at which the 00648 * assertion failed). 00649 * 00650 * For example "Cgu::DoIf::assert_same_type<A>(x)" will fail to 00651 * compile unless the static type of 'x' is type A. In making this 00652 * test, constness is discarded and not taken into account: types can 00653 * be the same even if one is const and the other is not. 00654 * 00655 * It generates no object code, and is therefore thread safe and does 00656 * not throw. 00657 * 00658 * Earlier versions of this function had a bug. A const type could 00659 * not be specified as the explicit template argument 00660 * (Cgu::DoIf::assert_same_type<const A>(x) would not work). This was 00661 * fixed in version 2.0.1. 00662 */ 00663 template <class T1, class T2> 00664 void assert_same_type(const T2& t2) { 00665 // in the second conditional test, make T2 const in case the user 00666 // specifies a const T1 parameter type 00667 static_assert(RelatedTest<T1, T2>::value && RelatedTest<const T2, T1>::value, 00668 "Cgu::DoIf::assert_same_type() failed"); 00669 } 00670 00671 /** 00672 * This function provides a compile time assertion that the static 00673 * type of the arguments passed are related to each other (that is, 00674 * either they are the same or one is publicly derived from the 00675 * other). If they are not, a compile time error will occur (with a 00676 * message that "Cgu::DoIf::assert_related_types() failed", and the 00677 * line at which this function is reported as instantiated will be the 00678 * line at which the assertion failed). 00679 * 00680 * For example "Cgu::DoIf::assert_related_types(a, b)" will fail to 00681 * compile unless the static types of 'a' and 'b' are the same or one 00682 * of the static types is publicly derived from the other. In making 00683 * this test, constness is discarded and not taken into account: types 00684 * can be related even if one is const and the other is not. 00685 * 00686 * See assert_related_to_type() for a test where the ordering of the 00687 * arguments is significant, so that which of them must be the base 00688 * type can be stated. 00689 * 00690 * This function can be viewed as doing the opposite of 00691 * Cgu::DoIf::mem_fun() and Cgu::DoIf::fun(): it causes a compilation 00692 * error where the test is not met, rather than doing nothing. 00693 * However, unlike those functions, as mentioned above 00694 * assert_related_types() discards constness in making the test. 00695 * 00696 * It generates no object code, and is therefore thread safe and does 00697 * not throw. 00698 */ 00699 template <class T1, class T2> 00700 void assert_related_types(const T1& t1, const T2& t2) { 00701 static_assert(RelatedTest<T1, T2>::value || RelatedTest<T2, T1>::value, 00702 "Cgu::DoIf::assert_related_types() failed"); 00703 } 00704 00705 /** 00706 * This function provides a compile time assertion that the static 00707 * type of the argument passed is not const. If it is, a compile time 00708 * error will occur (with a message that 00709 * "Cgu::DoIf::assert_not_const() failed", and the line at which this 00710 * function is reported as instantiated will be the line at which the 00711 * assertion failed). 00712 * 00713 * For example 'Cgu::DoIf::assert_not_const(a)' will fail to compile 00714 * unless the static type of 'a' is not const. 00715 * 00716 * It generates no object code, and is therefore thread safe and does 00717 * not throw. 00718 * 00719 * Since 2.0.1 00720 */ 00721 template <class T> 00722 void assert_not_const(T& t) { 00723 static_assert(RelatedTest<typename std::remove_const<T>::type, T>::value, 00724 "Cgu::DoIf::assert_not_const() failed"); 00725 } 00726 00727 #ifndef DOXYGEN_PARSING 00728 00729 /* 00730 These classes and associated helper function employ 'RelatedTest' to 00731 implement conditional compilation using templates and derivation. 00732 They can be used with non-static class functions, static class 00733 functions. 00734 */ 00735 /* 00736 the static member functions for the 'false' specialisations take 00737 Args... rather just an elipsis argument so that any argument can be 00738 a non-POD type 00739 */ 00740 00741 template <bool value, class Ret> 00742 struct cond_call {}; 00743 00744 /* cond_call implementation */ 00745 00746 /* case of true with a return value */ 00747 00748 template <class Ret> 00749 struct cond_call<true, Ret> { 00750 template <class T, class Func, class... Args> 00751 static Ret exec(T& obj, 00752 Func func, 00753 Args&&... args) { 00754 return (obj.*func)(std::forward<Args>(args)...); 00755 } 00756 00757 template <class T, class Func, class... Args> 00758 static Ret exec_static(T& obj, 00759 Func func, 00760 Args&&... args) { 00761 return func(&obj, std::forward<Args>(args)...); 00762 } 00763 }; 00764 00765 /* case of false with a return value */ 00766 00767 template <class Ret> 00768 struct cond_call<false, Ret> { 00769 template <class T, class Func, class... Args> 00770 static Ret exec(T&, 00771 Func, 00772 Args&&...) { 00773 return Ret(); 00774 } 00775 00776 template <class T, class Func, class... Args> 00777 static Ret exec_static(T&, 00778 Func, 00779 Args&&...) { 00780 return Ret(); 00781 } 00782 }; 00783 00784 /* case of true with no return value */ 00785 00786 template <> 00787 struct cond_call<true, void> { 00788 template <class T, class Func, class... Args> 00789 static void exec(T& obj, 00790 Func func, 00791 Args&&... args) { 00792 (obj.*func)(std::forward<Args>(args)...); 00793 } 00794 00795 template <class T, class Func, class... Args> 00796 static void exec_static(T& obj, 00797 Func func, 00798 Args&&... args) { 00799 func(&obj, std::forward<Args>(args)...); 00800 } 00801 }; 00802 00803 /* case of false with no return value */ 00804 00805 template <> 00806 struct cond_call<false, void> { 00807 template <class T, class Func, class... Args> 00808 static void exec(T&, 00809 Func, 00810 Args&&...) {} 00811 00812 template <class T, class Func, class... Args> 00813 static void exec_static(T&, 00814 Func, 00815 Args&&...) {} 00816 }; 00817 00818 #endif /* DOXYGEN_PARSING */ 00819 00820 /* the mem_fun() forwarding functions */ 00821 00822 /* with return value */ 00823 00824 /** 00825 * This function overload conditionally executes the member function 00826 * passed as the second argument if the class object passed as the 00827 * first argument has it as a member (say by derivation), otherwise it 00828 * does nothing. This function is thread safe if the referenced 00829 * member function is thread safe. It does not throw unless the 00830 * referenced member function throws or (if its arguments are not 00831 * built-in types nor reference arguments) the copy constructor of one 00832 * of the member function's arguments throws, or (if no call is made) 00833 * the return type's default constructor throws. 00834 * @return The result of the function call, or if no call is made, an 00835 * empty object obtained by calling the return type's default 00836 * constructor. 00837 */ 00838 template <class Base, class Obj, class Ret, class... Params, class... Args> 00839 Ret mem_fun(Obj& obj, 00840 Ret (Base::*func)(Params...), 00841 Args&&... args) { 00842 return cond_call<RelatedTest<Base, Obj>::value, Ret>::exec(obj, func, 00843 std::forward<Args>(args)...); 00844 } 00845 00846 /* no return value */ 00847 00848 /** 00849 * This function overload conditionally executes the member function 00850 * passed as the second argument if the class object passed as the 00851 * first argument has it as a member (say by derivation), otherwise it 00852 * does nothing. This function is thread safe if the referenced 00853 * member function is thread safe. It does not throw unless the 00854 * referenced member function throws or (if its arguments are not 00855 * built-in types nor reference arguments) the copy constructor of one 00856 * of the member function's arguments throws. 00857 */ 00858 template <class Base, class Obj, class... Params, class... Args> 00859 void mem_fun(Obj& obj, 00860 void (Base::*func)(Params...), 00861 Args&&... args) { 00862 cond_call<RelatedTest<Base, Obj>::value, void>::exec(obj, func, 00863 std::forward<Args>(args)...); 00864 } 00865 00866 /* for const member functions */ 00867 00868 /* with return value */ 00869 00870 /** 00871 * This function overload conditionally executes the member function 00872 * passed as the second argument if the class object passed as the 00873 * first argument has it as a member (say by derivation), otherwise it 00874 * does nothing. This function is thread safe if the referenced 00875 * member function is thread safe. It does not throw unless the 00876 * referenced member function throws or (if its arguments are not 00877 * built-in types nor reference arguments) the copy constructor of one 00878 * of the member function's arguments throws, or (if no call is made) 00879 * the return type's default constructor throws. 00880 * @return The result of the function call, or if no call is made, an 00881 * empty object obtained by calling the return type's default 00882 * constructor. 00883 */ 00884 template <class Base, class Obj, class Ret, class... Params, class... Args> 00885 Ret mem_fun(const Obj& obj, 00886 Ret (Base::*func)(Params...) const, 00887 Args&&... args) { 00888 return cond_call<RelatedTest<Base, Obj>::value, Ret>::exec(obj, func, 00889 std::forward<Args>(args)...); 00890 } 00891 00892 /* no return value */ 00893 00894 /** 00895 * This function overload conditionally executes the member function 00896 * passed as the second argument if the class object passed as the 00897 * first argument has it as a member (say by derivation), otherwise it 00898 * does nothing. This function is thread safe if the referenced 00899 * member function is thread safe. It does not throw unless the 00900 * referenced member function throws or (if its arguments are not 00901 * built-in types nor reference arguments) the copy constructor of one 00902 * of the member function's arguments throws. 00903 */ 00904 template <class Base, class Obj, class... Params, class... Args> 00905 void mem_fun(const Obj& obj, 00906 void (Base::*func)(Params...) const, 00907 Args&&... args) { 00908 cond_call<RelatedTest<Base, Obj>::value, void>::exec(obj, func, 00909 std::forward<Args>(args)...); 00910 } 00911 00912 /* for ordinary functions and static member functions */ 00913 00914 /* with return value */ 00915 /** 00916 * This function overload conditionally executes the function passed 00917 * as the second argument if the object passed as the first argument 00918 * relates to (ie is an instance of or derived from) the type to which 00919 * the first argument of the function to be conditionally executed is 00920 * a pointer, otherwise it does nothing. This function is thread safe 00921 * if the referenced function to be called is thread safe. It does 00922 * not throw unless the referenced function throws or (if its 00923 * arguments are not built-in types nor reference arguments) the copy 00924 * constructor of one of the referenced function's arguments throws, 00925 * or (if no call is made) the return type's default constructor 00926 * throws. 00927 * @return The result of the function call, or if no call is made, an 00928 * empty object obtained by calling the return type's default 00929 * constructor. 00930 */ 00931 template <class Base, class Obj, class Ret, class... Params, class... Args> 00932 Ret fun(Obj& obj, 00933 Ret (*func)(Base*, Params...), 00934 Args&&... args) { 00935 return cond_call<RelatedTest<Base, Obj>::value, Ret>::exec_static(obj, func, 00936 std::forward<Args>(args)...); 00937 } 00938 00939 /* no return value */ 00940 00941 /** 00942 * This function overload conditionally executes the function passed 00943 * as the second argument if the object passed as the first argument 00944 * relates to (ie is an instance of or derived from) the type to which 00945 * the first argument of the function to be conditionally executed is 00946 * a pointer, otherwise it does nothing. This function is thread safe 00947 * if the referenced function to be called is thread safe. It does 00948 * not throw unless the referenced function throws or (if its 00949 * arguments are not built-in types nor reference arguments) the copy 00950 * constructor of one of the referenced function's arguments throws. 00951 */ 00952 template <class Base, class Obj, class... Params, class... Args> 00953 void fun(Obj& obj, 00954 void (*func)(Base*, Params...), 00955 Args&&... args) { 00956 cond_call<RelatedTest<Base, Obj>::value, void>::exec_static(obj, func, 00957 std::forward<Args>(args)...); 00958 } 00959 00960 } // namespace DoIf 00961 00962 } // namespace Cgu 00963 00964 #endif /* CGU_DO_IF */