|
1 /* Copyright 2003-2006 Joaquín M López Muñoz. |
|
2 * Distributed under the Boost Software License, Version 1.0. |
|
3 * (See accompanying file LICENSE_1_0.txt or copy at |
|
4 * http://www.boost.org/LICENSE_1_0.txt) |
|
5 * |
|
6 * See http://www.boost.org/libs/multi_index for library home page. |
|
7 */ |
|
8 |
|
9 #ifndef BOOST_MULTI_INDEX_MEMBER_HPP |
|
10 #define BOOST_MULTI_INDEX_MEMBER_HPP |
|
11 |
|
12 #if defined(_MSC_VER)&&(_MSC_VER>=1200) |
|
13 #pragma once |
|
14 #endif |
|
15 |
|
16 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ |
|
17 #include <boost/mpl/if.hpp> |
|
18 #include <boost/type_traits/is_const.hpp> |
|
19 #include <boost/utility/enable_if.hpp> |
|
20 #include <cstddef> |
|
21 |
|
22 #if !defined(BOOST_NO_SFINAE) |
|
23 #include <boost/type_traits/is_convertible.hpp> |
|
24 #endif |
|
25 |
|
26 namespace boost{ |
|
27 |
|
28 template<class T> class reference_wrapper; /* fwd decl. */ |
|
29 |
|
30 namespace multi_index{ |
|
31 |
|
32 namespace detail{ |
|
33 |
|
34 /* member is a read/write key extractor for accessing a given |
|
35 * member of a class. |
|
36 * Additionally, member is overloaded to support referece_wrappers |
|
37 * of T and "chained pointers" to T's. By chained pointer to T we mean |
|
38 * a type P such that, given a p of Type P |
|
39 * *...n...*x is convertible to T&, for some n>=1. |
|
40 * Examples of chained pointers are raw and smart pointers, iterators and |
|
41 * arbitrary combinations of these (vg. T** or auto_ptr<T*>.) |
|
42 */ |
|
43 |
|
44 /* NB. Some overloads of operator() have an extra dummy parameter int=0. |
|
45 * This disambiguator serves several purposes: |
|
46 * - Without it, MSVC++ 6.0 incorrectly regards some overloads as |
|
47 * specializations of a previous member function template. |
|
48 * - MSVC++ 6.0/7.0 seem to incorrectly treat some different memfuns |
|
49 * as if they have the same signature. |
|
50 * - If remove_const is broken due to lack of PTS, int=0 avoids the |
|
51 * declaration of memfuns with identical signature. |
|
52 */ |
|
53 |
|
54 template<class Class,typename Type,Type Class::*PtrToMember> |
|
55 struct const_member_base |
|
56 { |
|
57 typedef Type result_type; |
|
58 |
|
59 template<typename ChainedPtr> |
|
60 |
|
61 #if !defined(BOOST_NO_SFINAE) |
|
62 typename disable_if< |
|
63 is_convertible<const ChainedPtr&,const Class&>,Type&>::type |
|
64 #else |
|
65 Type& |
|
66 #endif |
|
67 |
|
68 operator()(const ChainedPtr& x)const |
|
69 { |
|
70 return operator()(*x); |
|
71 } |
|
72 |
|
73 Type& operator()(const Class& x)const |
|
74 { |
|
75 return x.*PtrToMember; |
|
76 } |
|
77 |
|
78 Type& operator()(const reference_wrapper<const Class>& x)const |
|
79 { |
|
80 return operator()(x.get()); |
|
81 } |
|
82 |
|
83 Type& operator()(const reference_wrapper<Class>& x,int=0)const |
|
84 { |
|
85 return operator()(x.get()); |
|
86 } |
|
87 }; |
|
88 |
|
89 template<class Class,typename Type,Type Class::*PtrToMember> |
|
90 struct non_const_member_base |
|
91 { |
|
92 typedef Type result_type; |
|
93 |
|
94 template<typename ChainedPtr> |
|
95 |
|
96 #if !defined(BOOST_NO_SFINAE) |
|
97 typename disable_if< |
|
98 is_convertible<const ChainedPtr&,const Class&>,Type&>::type |
|
99 #else |
|
100 Type& |
|
101 #endif |
|
102 |
|
103 operator()(const ChainedPtr& x)const |
|
104 { |
|
105 return operator()(*x); |
|
106 } |
|
107 |
|
108 const Type& operator()(const Class& x,int=0)const |
|
109 { |
|
110 return x.*PtrToMember; |
|
111 } |
|
112 |
|
113 Type& operator()(Class& x)const |
|
114 { |
|
115 return x.*PtrToMember; |
|
116 } |
|
117 |
|
118 const Type& operator()(const reference_wrapper<const Class>& x,int=0)const |
|
119 { |
|
120 return operator()(x.get()); |
|
121 } |
|
122 |
|
123 Type& operator()(const reference_wrapper<Class>& x)const |
|
124 { |
|
125 return operator()(x.get()); |
|
126 } |
|
127 }; |
|
128 |
|
129 } /* namespace multi_index::detail */ |
|
130 |
|
131 template<class Class,typename Type,Type Class::*PtrToMember> |
|
132 struct member: |
|
133 mpl::if_c< |
|
134 is_const<Type>::value, |
|
135 detail::const_member_base<Class,Type,PtrToMember>, |
|
136 detail::non_const_member_base<Class,Type,PtrToMember> |
|
137 >::type |
|
138 { |
|
139 }; |
|
140 |
|
141 namespace detail{ |
|
142 |
|
143 /* MSVC++ 6.0 does not support properly pointers to members as |
|
144 * non-type template arguments, as reported in |
|
145 * http://support.microsoft.com/default.aspx?scid=kb;EN-US;249045 |
|
146 * A similar problem (though not identical) is shown by MSVC++ 7.0. |
|
147 * We provide an alternative to member<> accepting offsets instead |
|
148 * of pointers to members. This happens to work even for non-POD |
|
149 * types (although the standard forbids use of offsetof on these), |
|
150 * so it serves as a workaround in this compiler for all practical |
|
151 * purposes. |
|
152 * Surprisingly enough, other compilers, like Intel C++ 7.0/7.1 and |
|
153 * Visual Age 6.0, have similar bugs. This replacement of member<> |
|
154 * can be used for them too. |
|
155 */ |
|
156 |
|
157 template<class Class,typename Type,std::size_t OffsetOfMember> |
|
158 struct const_member_offset_base |
|
159 { |
|
160 typedef Type result_type; |
|
161 |
|
162 template<typename ChainedPtr> |
|
163 |
|
164 #if !defined(BOOST_NO_SFINAE) |
|
165 typename disable_if< |
|
166 is_convertible<const ChainedPtr&,const Class&>,Type&>::type |
|
167 #else |
|
168 Type& |
|
169 #endif |
|
170 |
|
171 operator()(const ChainedPtr& x)const |
|
172 { |
|
173 return operator()(*x); |
|
174 } |
|
175 |
|
176 Type& operator()(const Class& x)const |
|
177 { |
|
178 return *static_cast<const Type*>( |
|
179 static_cast<const void*>( |
|
180 static_cast<const char*>( |
|
181 static_cast<const void *>(&x))+OffsetOfMember)); |
|
182 } |
|
183 |
|
184 Type& operator()(const reference_wrapper<const Class>& x)const |
|
185 { |
|
186 return operator()(x.get()); |
|
187 } |
|
188 |
|
189 Type& operator()(const reference_wrapper<Class>& x,int=0)const |
|
190 { |
|
191 return operator()(x.get()); |
|
192 } |
|
193 }; |
|
194 |
|
195 template<class Class,typename Type,std::size_t OffsetOfMember> |
|
196 struct non_const_member_offset_base |
|
197 { |
|
198 typedef Type result_type; |
|
199 |
|
200 template<typename ChainedPtr> |
|
201 |
|
202 #if !defined(BOOST_NO_SFINAE) |
|
203 typename disable_if< |
|
204 is_convertible<const ChainedPtr&,const Class&>,Type&>::type |
|
205 #else |
|
206 Type& |
|
207 #endif |
|
208 |
|
209 operator()(const ChainedPtr& x)const |
|
210 { |
|
211 return operator()(*x); |
|
212 } |
|
213 |
|
214 const Type& operator()(const Class& x,int=0)const |
|
215 { |
|
216 return *static_cast<const Type*>( |
|
217 static_cast<const void*>( |
|
218 static_cast<const char*>( |
|
219 static_cast<const void *>(&x))+OffsetOfMember)); |
|
220 } |
|
221 |
|
222 Type& operator()(Class& x)const |
|
223 { |
|
224 return *static_cast<Type*>( |
|
225 static_cast<void*>( |
|
226 static_cast<char*>(static_cast<void *>(&x))+OffsetOfMember)); |
|
227 } |
|
228 |
|
229 const Type& operator()(const reference_wrapper<const Class>& x,int=0)const |
|
230 { |
|
231 return operator()(x.get()); |
|
232 } |
|
233 |
|
234 Type& operator()(const reference_wrapper<Class>& x)const |
|
235 { |
|
236 return operator()(x.get()); |
|
237 } |
|
238 }; |
|
239 |
|
240 } /* namespace multi_index::detail */ |
|
241 |
|
242 template<class Class,typename Type,std::size_t OffsetOfMember> |
|
243 struct member_offset: |
|
244 mpl::if_c< |
|
245 is_const<Type>::value, |
|
246 detail::const_member_offset_base<Class,Type,OffsetOfMember>, |
|
247 detail::non_const_member_offset_base<Class,Type,OffsetOfMember> |
|
248 >::type |
|
249 { |
|
250 }; |
|
251 |
|
252 /* BOOST_MULTI_INDEX_MEMBER resolves to member in the normal cases, |
|
253 * and to member_offset as a workaround in those defective compilers for |
|
254 * which BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS is defined. |
|
255 */ |
|
256 |
|
257 #if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) |
|
258 #define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \ |
|
259 ::boost::multi_index::member_offset< Class,Type,offsetof(Class,MemberName) > |
|
260 #else |
|
261 #define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \ |
|
262 ::boost::multi_index::member< Class,Type,&Class::MemberName > |
|
263 #endif |
|
264 |
|
265 } /* namespace multi_index */ |
|
266 |
|
267 } /* namespace boost */ |
|
268 |
|
269 #endif |