Line data Source code
1 : /* Copyright 2003-2015 Joaquin M Lopez Munoz.
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)
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 unique_ptr<T*>.)
42 : */
43 :
44 : template<class Class,typename Type,Type Class::*PtrToMember>
45 : struct const_member_base
46 : {
47 : typedef Type result_type;
48 :
49 : template<typename ChainedPtr>
50 :
51 : #if !defined(BOOST_NO_SFINAE)
52 : typename disable_if<
53 : is_convertible<const ChainedPtr&,const Class&>,Type&>::type
54 : #else
55 : Type&
56 : #endif
57 :
58 : operator()(const ChainedPtr& x)const
59 : {
60 : return operator()(*x);
61 : }
62 :
63 : Type& operator()(const Class& x)const
64 : {
65 : return x.*PtrToMember;
66 : }
67 :
68 : Type& operator()(const reference_wrapper<const Class>& x)const
69 : {
70 : return operator()(x.get());
71 : }
72 :
73 : Type& operator()(const reference_wrapper<Class>& x)const
74 : {
75 : return operator()(x.get());
76 : }
77 : };
78 :
79 : template<class Class,typename Type,Type Class::*PtrToMember>
80 : struct non_const_member_base
81 : {
82 : typedef Type result_type;
83 :
84 : template<typename ChainedPtr>
85 :
86 : #if !defined(BOOST_NO_SFINAE)
87 : typename disable_if<
88 : is_convertible<const ChainedPtr&,const Class&>,Type&>::type
89 : #else
90 : Type&
91 : #endif
92 :
93 : operator()(const ChainedPtr& x)const
94 : {
95 : return operator()(*x);
96 : }
97 :
98 0 : const Type& operator()(const Class& x)const
99 : {
100 0 : return x.*PtrToMember;
101 : }
102 :
103 0 : Type& operator()(Class& x)const
104 : {
105 0 : return x.*PtrToMember;
106 : }
107 :
108 : const Type& operator()(const reference_wrapper<const Class>& x)const
109 : {
110 : return operator()(x.get());
111 : }
112 :
113 : Type& operator()(const reference_wrapper<Class>& x)const
114 : {
115 : return operator()(x.get());
116 : }
117 : };
118 :
119 : } /* namespace multi_index::detail */
120 :
121 : template<class Class,typename Type,Type Class::*PtrToMember>
122 : struct member:
123 : mpl::if_c<
124 : is_const<Type>::value,
125 : detail::const_member_base<Class,Type,PtrToMember>,
126 : detail::non_const_member_base<Class,Type,PtrToMember>
127 : >::type
128 : {
129 : };
130 :
131 : namespace detail{
132 :
133 : /* MSVC++ 6.0 does not support properly pointers to members as
134 : * non-type template arguments, as reported in
135 : * http://support.microsoft.com/default.aspx?scid=kb;EN-US;249045
136 : * A similar problem (though not identical) is shown by MSVC++ 7.0.
137 : * We provide an alternative to member<> accepting offsets instead
138 : * of pointers to members. This happens to work even for non-POD
139 : * types (although the standard forbids use of offsetof on these),
140 : * so it serves as a workaround in this compiler for all practical
141 : * purposes.
142 : * Surprisingly enough, other compilers, like Intel C++ 7.0/7.1 and
143 : * Visual Age 6.0, have similar bugs. This replacement of member<>
144 : * can be used for them too.
145 : *
146 : * Support for such old compilers is dropped and
147 : * [non_]const_member_offset_base is deprecated.
148 : */
149 :
150 : template<class Class,typename Type,std::size_t OffsetOfMember>
151 : struct const_member_offset_base
152 : {
153 : typedef Type result_type;
154 :
155 : template<typename ChainedPtr>
156 :
157 : #if !defined(BOOST_NO_SFINAE)
158 : typename disable_if<
159 : is_convertible<const ChainedPtr&,const Class&>,Type&>::type
160 : #else
161 : Type&
162 : #endif
163 :
164 : operator()(const ChainedPtr& x)const
165 : {
166 : return operator()(*x);
167 : }
168 :
169 : Type& operator()(const Class& x)const
170 : {
171 : return *static_cast<const Type*>(
172 : static_cast<const void*>(
173 : static_cast<const char*>(
174 : static_cast<const void *>(&x))+OffsetOfMember));
175 : }
176 :
177 : Type& operator()(const reference_wrapper<const Class>& x)const
178 : {
179 : return operator()(x.get());
180 : }
181 :
182 : Type& operator()(const reference_wrapper<Class>& x)const
183 : {
184 : return operator()(x.get());
185 : }
186 : };
187 :
188 : template<class Class,typename Type,std::size_t OffsetOfMember>
189 : struct non_const_member_offset_base
190 : {
191 : typedef Type result_type;
192 :
193 : template<typename ChainedPtr>
194 :
195 : #if !defined(BOOST_NO_SFINAE)
196 : typename disable_if<
197 : is_convertible<const ChainedPtr&,const Class&>,Type&>::type
198 : #else
199 : Type&
200 : #endif
201 :
202 : operator()(const ChainedPtr& x)const
203 : {
204 : return operator()(*x);
205 : }
206 :
207 : const Type& operator()(const Class& x)const
208 : {
209 : return *static_cast<const Type*>(
210 : static_cast<const void*>(
211 : static_cast<const char*>(
212 : static_cast<const void *>(&x))+OffsetOfMember));
213 : }
214 :
215 : Type& operator()(Class& x)const
216 : {
217 : return *static_cast<Type*>(
218 : static_cast<void*>(
219 : static_cast<char*>(static_cast<void *>(&x))+OffsetOfMember));
220 : }
221 :
222 : const Type& operator()(const reference_wrapper<const Class>& x)const
223 : {
224 : return operator()(x.get());
225 : }
226 :
227 : Type& operator()(const reference_wrapper<Class>& x)const
228 : {
229 : return operator()(x.get());
230 : }
231 : };
232 :
233 : } /* namespace multi_index::detail */
234 :
235 : template<class Class,typename Type,std::size_t OffsetOfMember>
236 : struct member_offset:
237 : mpl::if_c<
238 : is_const<Type>::value,
239 : detail::const_member_offset_base<Class,Type,OffsetOfMember>,
240 : detail::non_const_member_offset_base<Class,Type,OffsetOfMember>
241 : >::type
242 : {
243 : };
244 :
245 : /* BOOST_MULTI_INDEX_MEMBER resolves to member in the normal cases,
246 : * and to member_offset as a workaround in those defective compilers for
247 : * which BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS is defined.
248 : */
249 :
250 : #if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS)
251 : #define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \
252 : ::boost::multi_index::member_offset< Class,Type,offsetof(Class,MemberName) >
253 : #else
254 : #define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \
255 : ::boost::multi_index::member< Class,Type,&Class::MemberName >
256 : #endif
257 :
258 : } /* namespace multi_index */
259 :
260 : } /* namespace boost */
261 :
262 : #endif
|