1 // -*- c++ -*- 2 /* 3 * Copyright 2002, The libsigc++ Development Team 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 */ 20 #ifndef _SIGC_VISIT_EACH_HPP_ 21 #define _SIGC_VISIT_EACH_HPP_ 22 23 #include <sigc++/type_traits.h> 24 25 namespace sigc { 26 27 namespace internal { 28 29 //This should really be an inner class of limit_derived_target, without the T_limit template type, 30 //But the SUN CC 5.7 (not earlier versions) compiler finds it ambiguous when we specify a particular specialization of it. 31 //and does not seem to allow us to tell it explicitly that it's an inner class. 32 template <bool I_derived, class T_type, class T_limit> 33 struct with_type; 34 35 //Specialization for I_derived = false 36 template <class T_type, class T_limit> struct 37 with_type<false, T_type, T_limit> 38 { 39 static void execute_(const T_type&, const T_limit&) {} 40 }; 41 42 //Specialization for I_derived = true 43 template <class T_type, class T_limit> 44 struct with_type<true, T_type, T_limit> 45 { 46 static void execute_(const T_type& _A_type, const T_limit& _A_action) 47 { _A_action.action_(_A_type); } 48 }; 49 50 51 /// Helper struct for visit_each_type(). 52 template <class T_target, class T_action> 53 struct limit_derived_target 54 { 55 typedef limit_derived_target<T_target, T_action> T_self; 56 57 58 template <class T_type> 59 void operator()(const T_type& _A_type) const 60 { 61 with_type<is_base_and_derived<T_target, T_type>::value, T_type, T_self>::execute_(_A_type, *this); 62 } 63 64 limit_derived_target(const T_action& _A_action) 65 : action_(_A_action) 66 {} 67 68 T_action action_; 69 }; 70 71 // Specialization for T_target pointer types, to provide a slightly different execute_() implementation. 72 73 template <bool I_derived, class T_type, class T_limit> 74 struct with_type_pointer; 75 76 //Specialization for I_derived = false 77 template <class T_type, class T_limit> 78 struct with_type_pointer<false, T_type, T_limit> 79 { 80 static void execute_(const T_type&, const T_limit&) {} 81 }; 82 83 //Specialization for I_derived = true 84 template <class T_type, class T_limit> 85 struct with_type_pointer<true, T_type, T_limit> 86 { 87 static void execute_(const T_type& _A_type, const T_limit& _A_action) 88 { _A_action.action_(&_A_type); } 89 }; 90 91 template <class T_target, class T_action> 92 struct limit_derived_target<T_target*, T_action> 93 { 94 typedef limit_derived_target<T_target*, T_action> T_self; 95 96 97 template <class T_type> 98 void operator()(const T_type& _A_type) const 99 { 100 with_type_pointer<is_base_and_derived<T_target, T_type>::value, T_type, T_self>::execute_(_A_type, *this); 101 } 102 103 limit_derived_target(const T_action& _A_action) 104 : action_(_A_action) 105 {} 106 107 T_action action_; 108 }; 109 110 } /* namespace internal */ 111 112 113 /** This function performs a functor on each of the targets of a functor. 114 * All unknown types just call @e _A_action on them. 115 * Add overloads that specialize the @e T_functor argument for your own 116 * functor types, so that subobjects get visited. This is needed to enable 117 * auto-disconnection support for your functor types. 118 * 119 * @par Example: 120 * @code 121 * struct some_functor 122 * { 123 * void operator()() {} 124 * some_possibly_sigc_trackable_derived_type some_data_member; 125 * some_other_functor_type some_other_functor; 126 * } 127 * 128 * namespace sigc 129 * { 130 * template <class T_action> 131 * void visit_each(const T_action& _A_action, 132 * const some_functor& _A_target) 133 * { 134 * visit_each(_A_action, _A_target.some_data_member); 135 * visit_each(_A_action, _A_target.some_other_functor); 136 * } 137 * } 138 * @endcode 139 * 140 * @ingroup functors 141 */ 142 template <class T_action, class T_functor> 143 void visit_each(const T_action& _A_action, const T_functor& _A_functor) 144 { _A_action(_A_functor); } 145 146 /** This function performs a functor on each of the targets 147 * of a functor limited to a restricted type. 148 * 149 * @ingroup functors 150 */ 151 template <class T_type, class T_action, class T_functor> 152 void visit_each_type(const T_action& _A_action, const T_functor& _A_functor) 153 { 154 typedef internal::limit_derived_target<T_type, T_action> type_limited_action; 155 156 type_limited_action limited_action(_A_action); 157 158 //specifying the types of the template specialization prevents disconnection of bound trackable references (such as with sigc::ref()), 159 //probably because the visit_each<> specializations take various different template types, 160 //in various sequences, and we are probably specifying only a subset of them with this. 161 // 162 //But this is required by the AIX (and maybe IRIX MipsPro and Tru64) compilers. 163 //I guess that sigc::ref() therefore does not work on those platforms. murrayc 164 //visit_each<type_limited_action, T_functor>(limited_action, _A_functor); 165 166 //g++ (even slightly old ones) is our primary platform, so we could use the non-crashing version. 167 //However, the expliict version also fixes a crash in a slightl more common case: http://bugzilla.gnome.org/show_bug.cgi?id=169225 168 //Users (and distributors) of libsigc++ on AIX (and maybe IRIX MipsPro and Tru64) do 169 //need to use the version above instead, to allow compilation. 170 visit_each(limited_action, _A_functor); 171 } 172 173 } /* namespace sigc */ 174 #endif 175