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