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)
 
     6  * See http://www.boost.org/libs/multi_index for library home page.
 
     9 #ifndef BOOST_MULTI_INDEX_MEMBER_HPP
 
    10 #define BOOST_MULTI_INDEX_MEMBER_HPP
 
    12 #if defined(_MSC_VER)&&(_MSC_VER>=1200)
 
    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>
 
    22 #if !defined(BOOST_NO_SFINAE)
 
    23 #include <boost/type_traits/is_convertible.hpp>
 
    28 template<class T> class reference_wrapper; /* fwd decl. */
 
    30 namespace multi_index{
 
    34 /* member is a read/write key extractor for accessing a given
 
    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*>.)
 
    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.
 
    54 template<class Class,typename Type,Type Class::*PtrToMember>
 
    55 struct const_member_base
 
    57   typedef Type result_type;
 
    59   template<typename ChainedPtr>
 
    61 #if !defined(BOOST_NO_SFINAE)
 
    63     is_convertible<const ChainedPtr&,const Class&>,Type&>::type
 
    68   operator()(const ChainedPtr& x)const
 
    70     return operator()(*x);
 
    73   Type& operator()(const Class& x)const
 
    75     return x.*PtrToMember;
 
    78   Type& operator()(const reference_wrapper<const Class>& x)const
 
    80     return operator()(x.get());
 
    83   Type& operator()(const reference_wrapper<Class>& x,int=0)const
 
    85     return operator()(x.get());
 
    89 template<class Class,typename Type,Type Class::*PtrToMember>
 
    90 struct non_const_member_base
 
    92   typedef Type result_type;
 
    94   template<typename ChainedPtr>
 
    96 #if !defined(BOOST_NO_SFINAE)
 
    98     is_convertible<const ChainedPtr&,const Class&>,Type&>::type
 
   103   operator()(const ChainedPtr& x)const
 
   105     return operator()(*x);
 
   108   const Type& operator()(const Class& x,int=0)const
 
   110     return x.*PtrToMember;
 
   113   Type& operator()(Class& x)const
 
   115     return x.*PtrToMember;
 
   118   const Type& operator()(const reference_wrapper<const Class>& x,int=0)const
 
   120     return operator()(x.get());
 
   123   Type& operator()(const reference_wrapper<Class>& x)const
 
   125     return operator()(x.get());
 
   129 } /* namespace multi_index::detail */
 
   131 template<class Class,typename Type,Type Class::*PtrToMember>
 
   134     is_const<Type>::value,
 
   135     detail::const_member_base<Class,Type,PtrToMember>,
 
   136     detail::non_const_member_base<Class,Type,PtrToMember>
 
   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
 
   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.
 
   157 template<class Class,typename Type,std::size_t OffsetOfMember>
 
   158 struct const_member_offset_base
 
   160   typedef Type result_type;
 
   162   template<typename ChainedPtr>
 
   164 #if !defined(BOOST_NO_SFINAE)
 
   166     is_convertible<const ChainedPtr&,const Class&>,Type&>::type
 
   171   operator()(const ChainedPtr& x)const
 
   173     return operator()(*x);
 
   176   Type& operator()(const Class& x)const
 
   178     return *static_cast<const Type*>(
 
   179       static_cast<const void*>(
 
   180         static_cast<const char*>(
 
   181           static_cast<const void *>(&x))+OffsetOfMember));
 
   184   Type& operator()(const reference_wrapper<const Class>& x)const
 
   186     return operator()(x.get());
 
   189   Type& operator()(const reference_wrapper<Class>& x,int=0)const
 
   191     return operator()(x.get());
 
   195 template<class Class,typename Type,std::size_t OffsetOfMember>
 
   196 struct non_const_member_offset_base
 
   198   typedef Type result_type;
 
   200   template<typename ChainedPtr>
 
   202 #if !defined(BOOST_NO_SFINAE)
 
   204     is_convertible<const ChainedPtr&,const Class&>,Type&>::type
 
   209   operator()(const ChainedPtr& x)const
 
   211     return operator()(*x);
 
   214   const Type& operator()(const Class& x,int=0)const
 
   216     return *static_cast<const Type*>(
 
   217       static_cast<const void*>(
 
   218         static_cast<const char*>(
 
   219           static_cast<const void *>(&x))+OffsetOfMember));
 
   222   Type& operator()(Class& x)const
 
   224     return *static_cast<Type*>(
 
   226         static_cast<char*>(static_cast<void *>(&x))+OffsetOfMember));
 
   229   const Type& operator()(const reference_wrapper<const Class>& x,int=0)const
 
   231     return operator()(x.get());
 
   234   Type& operator()(const reference_wrapper<Class>& x)const
 
   236     return operator()(x.get());
 
   240 } /* namespace multi_index::detail */
 
   242 template<class Class,typename Type,std::size_t OffsetOfMember>
 
   243 struct member_offset:
 
   245     is_const<Type>::value,
 
   246     detail::const_member_offset_base<Class,Type,OffsetOfMember>,
 
   247     detail::non_const_member_offset_base<Class,Type,OffsetOfMember>
 
   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.
 
   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) >
 
   261 #define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \
 
   262 ::boost::multi_index::member< Class,Type,&Class::MemberName >
 
   265 } /* namespace multi_index */
 
   267 } /* namespace boost */