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