]> git.tdb.fi Git - ext/sigc++-2.0.git/blob - sigc++/visit_each.h
Adjust the name of the library to match upstream
[ext/sigc++-2.0.git] / sigc++ / visit_each.h
1 /*
2  * Copyright 2002, The libsigc++ Development Team
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2.1 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */
18 #ifndef _SIGC_VISIT_EACH_HPP_
19 #define _SIGC_VISIT_EACH_HPP_
20
21 #include <sigc++/type_traits.h>
22 #include <type_traits>
23
24 namespace sigc {
25
26 #ifndef DOXYGEN_SHOULD_SKIP_THIS
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   template <class T_type>
58   void operator()(const T_type& _A_type) const
59   {
60     with_type<std::is_base_of<T_target, T_type>::value || std::is_same<T_target, T_type>::value, T_type, T_self>::execute_(_A_type, *this);
61   }
62
63   limit_derived_target(const T_action& _A_action)
64   : action_(_A_action)
65   {}
66
67   T_action action_;
68 };
69
70 // Specialization for T_target pointer types, to provide a slightly different execute_() implementation.
71
72 template <bool I_derived, class T_type, class T_limit>
73 struct with_type_pointer;
74
75 //Specialization for I_derived = false
76 template <class T_type, class T_limit>
77 struct with_type_pointer<false, T_type, T_limit>
78 {
79  static void execute_(const T_type&, const T_limit&) {}
80 };
81
82 //Specialization for I_derived = true
83 template <class T_type, class T_limit>
84 struct with_type_pointer<true, T_type, T_limit>
85 {
86   static void execute_(const T_type& _A_type, const T_limit& _A_action)
87   { _A_action.action_(&_A_type); }
88 };
89
90 template <class T_target, class T_action>
91 struct limit_derived_target<T_target*, T_action>
92 {
93   typedef limit_derived_target<T_target*, T_action> T_self;
94
95   template <class T_type>
96   void operator()(const T_type& _A_type) const
97   {
98     with_type_pointer<std::is_base_of<T_target, T_type>::value || std::is_same<T_target, T_type>::value, T_type, T_self>::execute_(_A_type, *this);
99   }
100
101   limit_derived_target(const T_action& _A_action)
102   : action_(_A_action)
103   {}
104
105   T_action action_;
106 };
107
108 } /* namespace internal */
109 #endif // DOXYGEN_SHOULD_SKIP_THIS
110
111 // struct visitor was introduced as a result of https://bugzilla.gnome.org/show_bug.cgi?id=724496
112 // The advantage of using specializations of a template struct instead of overloads of
113 // a template function is described by Herb Sutter in http://www.gotw.ca/publications/mill17.htm
114 // In libsigc++ the main reason for using this technique is that we can avoid using ADL
115 // (argument-dependent lookup), and therefore there is no risk that a visit_each() overload
116 // in e.g. Boost is selected by mistake.
117
118 /** sigc::visitor<T_functor>::do_visit_each() performs a functor on each of the targets of a functor.
119  * All unknown types just call @a _A_action on them.
120  * Add specializations that specialize the @a T_functor argument for your own
121  * functor types, so that subobjects get visited. This is needed to enable
122  * auto-disconnection support for your functor types.
123  *
124  * @par Example:
125  *   @code
126  *   namespace some_ns
127  *   {
128  *     struct some_functor
129  *     {
130  *       void operator()() {}
131  *       some_possibly_sigc_trackable_derived_type some_data_member;
132  *       some_other_functor_type some_other_functor;
133  *     };
134  *   }
135  *
136  *   namespace sigc
137  *   {
138  *     template <>
139  *     struct visitor<some_ns::some_functor>
140  *     {
141  *       template <class T_action>
142  *       static void do_visit_each(const T_action& _A_action,
143  *                                 const some_ns::some_functor& _A_target)
144  *       {
145  *         sigc::visit_each(_A_action, _A_target.some_data_member);
146  *         sigc::visit_each(_A_action, _A_target.some_other_functor);
147  *       }
148  *     };
149  *   }
150  *   @endcode
151  *
152  * @ingroup sigcfunctors
153  */
154 template <class T_functor>
155 struct visitor
156 {
157   template <class T_action>
158   static void do_visit_each(const T_action& _A_action, const T_functor& _A_functor)
159   {
160     _A_action(_A_functor);
161   }
162 };
163
164 /** This function performs a functor on each of the targets of a functor.
165  *
166  * @ingroup sigcfunctors
167  */
168 template <class T_action, class T_functor>
169 void visit_each(const T_action& _A_action, const T_functor& _A_functor)
170 { sigc::visitor<T_functor>::do_visit_each(_A_action, _A_functor); }
171
172 /** This function performs a functor on each of the targets
173  * of a functor limited to a restricted type.
174  *
175  * @ingroup sigcfunctors
176  */
177 template <class T_type, class T_action, class T_functor>
178 void visit_each_type(const T_action& _A_action, const T_functor& _A_functor)
179 {
180   typedef internal::limit_derived_target<T_type, T_action> type_limited_action;
181
182   type_limited_action limited_action(_A_action);
183
184   //specifying the types of the template specialization prevents disconnection of bound trackable references (such as with std::ref()),
185   //probably because the visit_each<> specializations take various different template types,
186   //in various sequences, and we are probably specifying only a subset of them with this.
187   //
188   //But this is required by the AIX (and maybe IRIX MipsPro  and Tru64) compilers.
189   //I guess that std::ref() therefore does not work on those platforms. murrayc
190   // sigc::visit_each<type_limited_action, T_functor>(limited_action, _A_functor);
191
192   //g++ (even slightly old ones) is our primary platform, so we could use the non-crashing version.
193   //However, the explicit version also fixes a crash in a slightly more common case: http://bugzilla.gnome.org/show_bug.cgi?id=169225
194   //Users (and distributors) of libsigc++ on AIX (and maybe IRIX MipsPro and Tru64) do
195   //need to use the version above instead, to allow compilation.
196
197   //Added 2014-03-20: The preceding comment probably does not apply any more,
198   //now when the visit_each<>() overloads have been replaced by visitor<> specializations.
199   //It's probably safe to add explicit template parameters on calls to visit_each(),
200   //visit_each_type() and visitor::do_visit_each(), if necessary.
201
202   sigc::visit_each(limited_action, _A_functor);
203 }
204
205 } /* namespace sigc */
206 #endif