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 operator ()boost::multi_index::detail::const_member_base58 operator()(const ChainedPtr& x)const 59 { 60 return operator()(*x); 61 } 62 operator ()boost::multi_index::detail::const_member_base63 Type& operator()(const Class& x)const 64 { 65 return x.*PtrToMember; 66 } 67 operator ()boost::multi_index::detail::const_member_base68 Type& operator()(const reference_wrapper<const Class>& x)const 69 { 70 return operator()(x.get()); 71 } 72 operator ()boost::multi_index::detail::const_member_base73 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 operator ()boost::multi_index::detail::non_const_member_base93 operator()(const ChainedPtr& x)const 94 { 95 return operator()(*x); 96 } 97 operator ()boost::multi_index::detail::non_const_member_base98 const Type& operator()(const Class& x)const 99 { 100 return x.*PtrToMember; 101 } 102 operator ()boost::multi_index::detail::non_const_member_base103 Type& operator()(Class& x)const 104 { 105 return x.*PtrToMember; 106 } 107 operator ()boost::multi_index::detail::non_const_member_base108 const Type& operator()(const reference_wrapper<const Class>& x)const 109 { 110 return operator()(x.get()); 111 } 112 operator ()boost::multi_index::detail::non_const_member_base113 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 operator ()boost::multi_index::detail::const_member_offset_base164 operator()(const ChainedPtr& x)const 165 { 166 return operator()(*x); 167 } 168 operator ()boost::multi_index::detail::const_member_offset_base169 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 operator ()boost::multi_index::detail::const_member_offset_base177 Type& operator()(const reference_wrapper<const Class>& x)const 178 { 179 return operator()(x.get()); 180 } 181 operator ()boost::multi_index::detail::const_member_offset_base182 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 operator ()boost::multi_index::detail::non_const_member_offset_base202 operator()(const ChainedPtr& x)const 203 { 204 return operator()(*x); 205 } 206 operator ()boost::multi_index::detail::non_const_member_offset_base207 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 operator ()boost::multi_index::detail::non_const_member_offset_base215 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 operator ()boost::multi_index::detail::non_const_member_offset_base222 const Type& operator()(const reference_wrapper<const Class>& x)const 223 { 224 return operator()(x.get()); 225 } 226 operator ()boost::multi_index::detail::non_const_member_offset_base227 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 263