williamr@2: /* Copyright 2003-2006 Joaquín M López Muñoz. williamr@2: * Distributed under the Boost Software License, Version 1.0. williamr@2: * (See accompanying file LICENSE_1_0.txt or copy at williamr@2: * http://www.boost.org/LICENSE_1_0.txt) williamr@2: * williamr@2: * See http://www.boost.org/libs/multi_index for library home page. williamr@2: */ williamr@2: williamr@2: #ifndef BOOST_MULTI_INDEX_MEMBER_HPP williamr@2: #define BOOST_MULTI_INDEX_MEMBER_HPP williamr@2: williamr@2: #if defined(_MSC_VER)&&(_MSC_VER>=1200) williamr@2: #pragma once williamr@2: #endif williamr@2: williamr@2: #include /* keep it first to prevent nasty warns in MSVC */ williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: williamr@2: #if !defined(BOOST_NO_SFINAE) williamr@2: #include williamr@2: #endif williamr@2: williamr@2: namespace boost{ williamr@2: williamr@2: template class reference_wrapper; /* fwd decl. */ williamr@2: williamr@2: namespace multi_index{ williamr@2: williamr@2: namespace detail{ williamr@2: williamr@2: /* member is a read/write key extractor for accessing a given williamr@2: * member of a class. williamr@2: * Additionally, member is overloaded to support referece_wrappers williamr@2: * of T and "chained pointers" to T's. By chained pointer to T we mean williamr@2: * a type P such that, given a p of Type P williamr@2: * *...n...*x is convertible to T&, for some n>=1. williamr@2: * Examples of chained pointers are raw and smart pointers, iterators and williamr@2: * arbitrary combinations of these (vg. T** or auto_ptr.) williamr@2: */ williamr@2: williamr@2: /* NB. Some overloads of operator() have an extra dummy parameter int=0. williamr@2: * This disambiguator serves several purposes: williamr@2: * - Without it, MSVC++ 6.0 incorrectly regards some overloads as williamr@2: * specializations of a previous member function template. williamr@2: * - MSVC++ 6.0/7.0 seem to incorrectly treat some different memfuns williamr@2: * as if they have the same signature. williamr@2: * - If remove_const is broken due to lack of PTS, int=0 avoids the williamr@2: * declaration of memfuns with identical signature. williamr@2: */ williamr@2: williamr@2: template williamr@2: struct const_member_base williamr@2: { williamr@2: typedef Type result_type; williamr@2: williamr@2: template williamr@2: williamr@2: #if !defined(BOOST_NO_SFINAE) williamr@2: typename disable_if< williamr@2: is_convertible,Type&>::type williamr@2: #else williamr@2: Type& williamr@2: #endif williamr@2: williamr@2: operator()(const ChainedPtr& x)const williamr@2: { williamr@2: return operator()(*x); williamr@2: } williamr@2: williamr@2: Type& operator()(const Class& x)const williamr@2: { williamr@2: return x.*PtrToMember; williamr@2: } williamr@2: williamr@2: Type& operator()(const reference_wrapper& x)const williamr@2: { williamr@2: return operator()(x.get()); williamr@2: } williamr@2: williamr@2: Type& operator()(const reference_wrapper& x,int=0)const williamr@2: { williamr@2: return operator()(x.get()); williamr@2: } williamr@2: }; williamr@2: williamr@2: template williamr@2: struct non_const_member_base williamr@2: { williamr@2: typedef Type result_type; williamr@2: williamr@2: template williamr@2: williamr@2: #if !defined(BOOST_NO_SFINAE) williamr@2: typename disable_if< williamr@2: is_convertible,Type&>::type williamr@2: #else williamr@2: Type& williamr@2: #endif williamr@2: williamr@2: operator()(const ChainedPtr& x)const williamr@2: { williamr@2: return operator()(*x); williamr@2: } williamr@2: williamr@2: const Type& operator()(const Class& x,int=0)const williamr@2: { williamr@2: return x.*PtrToMember; williamr@2: } williamr@2: williamr@2: Type& operator()(Class& x)const williamr@2: { williamr@2: return x.*PtrToMember; williamr@2: } williamr@2: williamr@2: const Type& operator()(const reference_wrapper& x,int=0)const williamr@2: { williamr@2: return operator()(x.get()); williamr@2: } williamr@2: williamr@2: Type& operator()(const reference_wrapper& x)const williamr@2: { williamr@2: return operator()(x.get()); williamr@2: } williamr@2: }; williamr@2: williamr@2: } /* namespace multi_index::detail */ williamr@2: williamr@2: template williamr@2: struct member: williamr@2: mpl::if_c< williamr@2: is_const::value, williamr@2: detail::const_member_base, williamr@2: detail::non_const_member_base williamr@2: >::type williamr@2: { williamr@2: }; williamr@2: williamr@2: namespace detail{ williamr@2: williamr@2: /* MSVC++ 6.0 does not support properly pointers to members as williamr@2: * non-type template arguments, as reported in williamr@2: * http://support.microsoft.com/default.aspx?scid=kb;EN-US;249045 williamr@2: * A similar problem (though not identical) is shown by MSVC++ 7.0. williamr@2: * We provide an alternative to member<> accepting offsets instead williamr@2: * of pointers to members. This happens to work even for non-POD williamr@2: * types (although the standard forbids use of offsetof on these), williamr@2: * so it serves as a workaround in this compiler for all practical williamr@2: * purposes. williamr@2: * Surprisingly enough, other compilers, like Intel C++ 7.0/7.1 and williamr@2: * Visual Age 6.0, have similar bugs. This replacement of member<> williamr@2: * can be used for them too. williamr@2: */ williamr@2: williamr@2: template williamr@2: struct const_member_offset_base williamr@2: { williamr@2: typedef Type result_type; williamr@2: williamr@2: template williamr@2: williamr@2: #if !defined(BOOST_NO_SFINAE) williamr@2: typename disable_if< williamr@2: is_convertible,Type&>::type williamr@2: #else williamr@2: Type& williamr@2: #endif williamr@2: williamr@2: operator()(const ChainedPtr& x)const williamr@2: { williamr@2: return operator()(*x); williamr@2: } williamr@2: williamr@2: Type& operator()(const Class& x)const williamr@2: { williamr@2: return *static_cast( williamr@2: static_cast( williamr@2: static_cast( williamr@2: static_cast(&x))+OffsetOfMember)); williamr@2: } williamr@2: williamr@2: Type& operator()(const reference_wrapper& x)const williamr@2: { williamr@2: return operator()(x.get()); williamr@2: } williamr@2: williamr@2: Type& operator()(const reference_wrapper& x,int=0)const williamr@2: { williamr@2: return operator()(x.get()); williamr@2: } williamr@2: }; williamr@2: williamr@2: template williamr@2: struct non_const_member_offset_base williamr@2: { williamr@2: typedef Type result_type; williamr@2: williamr@2: template williamr@2: williamr@2: #if !defined(BOOST_NO_SFINAE) williamr@2: typename disable_if< williamr@2: is_convertible,Type&>::type williamr@2: #else williamr@2: Type& williamr@2: #endif williamr@2: williamr@2: operator()(const ChainedPtr& x)const williamr@2: { williamr@2: return operator()(*x); williamr@2: } williamr@2: williamr@2: const Type& operator()(const Class& x,int=0)const williamr@2: { williamr@2: return *static_cast( williamr@2: static_cast( williamr@2: static_cast( williamr@2: static_cast(&x))+OffsetOfMember)); williamr@2: } williamr@2: williamr@2: Type& operator()(Class& x)const williamr@2: { williamr@2: return *static_cast( williamr@2: static_cast( williamr@2: static_cast(static_cast(&x))+OffsetOfMember)); williamr@2: } williamr@2: williamr@2: const Type& operator()(const reference_wrapper& x,int=0)const williamr@2: { williamr@2: return operator()(x.get()); williamr@2: } williamr@2: williamr@2: Type& operator()(const reference_wrapper& x)const williamr@2: { williamr@2: return operator()(x.get()); williamr@2: } williamr@2: }; williamr@2: williamr@2: } /* namespace multi_index::detail */ williamr@2: williamr@2: template williamr@2: struct member_offset: williamr@2: mpl::if_c< williamr@2: is_const::value, williamr@2: detail::const_member_offset_base, williamr@2: detail::non_const_member_offset_base williamr@2: >::type williamr@2: { williamr@2: }; williamr@2: williamr@2: /* BOOST_MULTI_INDEX_MEMBER resolves to member in the normal cases, williamr@2: * and to member_offset as a workaround in those defective compilers for williamr@2: * which BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS is defined. williamr@2: */ williamr@2: williamr@2: #if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) williamr@2: #define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \ williamr@2: ::boost::multi_index::member_offset< Class,Type,offsetof(Class,MemberName) > williamr@2: #else williamr@2: #define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \ williamr@2: ::boost::multi_index::member< Class,Type,&Class::MemberName > williamr@2: #endif williamr@2: williamr@2: } /* namespace multi_index */ williamr@2: williamr@2: } /* namespace boost */ williamr@2: williamr@2: #endif