1 2 // (C) Copyright Rani Sharoni 2003. 3 // Use, modification and distribution are subject to the Boost Software License, 4 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt). 6 // 7 // See http://www.boost.org/libs/type_traits for most recent version including documentation. 8 9 #ifndef BOOST_TT_IS_BASE_AND_DERIVED_HPP_INCLUDED 10 #define BOOST_TT_IS_BASE_AND_DERIVED_HPP_INCLUDED 11 12 #include "boost/type_traits/is_class.hpp" 13 #include "boost/type_traits/is_same.hpp" 14 #include "boost/type_traits/is_convertible.hpp" 15 #include "boost/type_traits/detail/ice_and.hpp" 16 #include "boost/type_traits/remove_cv.hpp" 17 #include "boost/config.hpp" 18 19 // should be the last #include 20 #include "boost/type_traits/detail/bool_trait_def.hpp" 21 22 namespace boost { 23 24 namespace detail { 25 26 #if !BOOST_WORKAROUND(__BORLANDC__, <= 0x570) \ 27 && !BOOST_WORKAROUND(__SUNPRO_CC , BOOST_TESTED_AT(0x540)) \ 28 && !BOOST_WORKAROUND(__EDG_VERSION__, <= 243) \ 29 && !BOOST_WORKAROUND(__DMC__, BOOST_TESTED_AT(0x840)) 30 31 // The EDG version number is a lower estimate. 32 // It is not currently known which EDG version 33 // exactly fixes the problem. 34 35 /************************************************************************* 36 37 This version detects ambiguous base classes and private base classes 38 correctly, and was devised by Rani Sharoni. 39 40 Explanation by Terje Sletteb� and Rani Sharoni. 41 42 Let's take the multiple base class below as an example, and the following 43 will also show why there's not a problem with private or ambiguous base 44 class: 45 46 struct B {}; 47 struct B1 : B {}; 48 struct B2 : B {}; 49 struct D : private B1, private B2 {}; 50 51 is_base_and_derived<B, D>::value; 52 53 First, some terminology: 54 55 SC - Standard conversion 56 UDC - User-defined conversion 57 58 A user-defined conversion sequence consists of an SC, followed by an UDC, 59 followed by another SC. Either SC may be the identity conversion. 60 61 When passing the default-constructed Host object to the overloaded check_sig() 62 functions (initialization 8.5/14/4/3), we have several viable implicit 63 conversion sequences: 64 65 For "static no_type check_sig(B const volatile *, int)" we have the conversion 66 sequences: 67 68 C -> C const (SC - Qualification Adjustment) -> B const volatile* (UDC) 69 C -> D const volatile* (UDC) -> B1 const volatile* / B2 const volatile* -> 70 B const volatile* (SC - Conversion) 71 72 For "static yes_type check_sig(D const volatile *, T)" we have the conversion 73 sequence: 74 75 C -> D const volatile* (UDC) 76 77 According to 13.3.3.1/4, in context of user-defined conversion only the 78 standard conversion sequence is considered when selecting the best viable 79 function, so it only considers up to the user-defined conversion. For the 80 first function this means choosing between C -> C const and C -> C, and it 81 chooses the latter, because it's a proper subset (13.3.3.2/3/2) of the 82 former. Therefore, we have: 83 84 C -> D const volatile* (UDC) -> B1 const volatile* / B2 const volatile* -> 85 B const volatile* (SC - Conversion) 86 C -> D const volatile* (UDC) 87 88 Here, the principle of the "shortest subsequence" applies again, and it 89 chooses C -> D const volatile*. This shows that it doesn't even need to 90 consider the multiple paths to B, or accessibility, as that possibility is 91 eliminated before it could possibly cause ambiguity or access violation. 92 93 If D is not derived from B, it has to choose between C -> C const -> B const 94 volatile* for the first function, and C -> D const volatile* for the second 95 function, which are just as good (both requires a UDC, 13.3.3.2), had it not 96 been for the fact that "static no_type check_sig(B const volatile *, int)" is 97 not templated, which makes C -> C const -> B const volatile* the best choice 98 (13.3.3/1/4), resulting in "no". 99 100 Also, if Host::operator B const volatile* hadn't been const, the two 101 conversion sequences for "static no_type check_sig(B const volatile *, int)", in 102 the case where D is derived from B, would have been ambiguous. 103 104 See also 105 http://groups.google.com/groups?selm=df893da6.0301280859.522081f7%40posting. 106 google.com and links therein. 107 108 *************************************************************************/ 109 110 template <typename B, typename D> 111 struct bd_helper 112 { 113 // 114 // This VC7.1 specific workaround stops the compiler from generating 115 // an internal compiler error when compiling with /vmg (thanks to 116 // Aleksey Gurtovoy for figuring out the workaround). 117 // 118 #if !BOOST_WORKAROUND(BOOST_MSVC, == 1310) 119 template <typename T> 120 static type_traits::yes_type check_sig(D const volatile *, T); 121 static type_traits::no_type check_sig(B const volatile *, int); 122 #else 123 static type_traits::yes_type check_sig(D const volatile *, long); 124 static type_traits::no_type check_sig(B const volatile * const&, int); 125 #endif 126 }; 127 128 template<typename B, typename D> 129 struct is_base_and_derived_impl2 130 { 131 struct Host 132 { 133 #if !BOOST_WORKAROUND(BOOST_MSVC, == 1310) 134 operator B const volatile *() const; 135 #else 136 operator B const volatile * const&() const; 137 #endif 138 operator D const volatile *(); 139 }; 140 141 BOOST_STATIC_CONSTANT(bool, value = 142 sizeof(bd_helper<B,D>::check_sig(Host(), 0)) == sizeof(type_traits::yes_type)); 143 }; 144 145 #else 146 147 // 148 // broken version: 149 // 150 template<typename B, typename D> 151 struct is_base_and_derived_impl2 152 { 153 BOOST_STATIC_CONSTANT(bool, value = 154 (::boost::is_convertible<D*,B*>::value)); 155 }; 156 157 #define BOOST_BROKEN_IS_BASE_AND_DERIVED 158 159 #endif 160 161 template <typename B, typename D> 162 struct is_base_and_derived_impl3 163 { 164 BOOST_STATIC_CONSTANT(bool, value = false); 165 }; 166 167 template <bool ic1, bool ic2, bool iss> 168 struct is_base_and_derived_select 169 { 170 template <class T, class U> 171 struct rebind 172 { 173 typedef is_base_and_derived_impl3<T,U> type; 174 }; 175 }; 176 177 template <> 178 struct is_base_and_derived_select<true,true,false> 179 { 180 template <class T, class U> 181 struct rebind 182 { 183 typedef is_base_and_derived_impl2<T,U> type; 184 }; 185 }; 186 187 template <typename B, typename D> 188 struct is_base_and_derived_impl 189 { 190 typedef typename remove_cv<B>::type ncvB; 191 typedef typename remove_cv<D>::type ncvD; 192 193 typedef is_base_and_derived_select< 194 ::boost::is_class<B>::value, 195 ::boost::is_class<D>::value, 196 ::boost::is_same<B,D>::value> selector; 197 typedef typename selector::template rebind<ncvB,ncvD> binder; 198 typedef typename binder::type bound_type; 199 200 BOOST_STATIC_CONSTANT(bool, value = bound_type::value); 201 }; 202 203 } // namespace detail 204 205 BOOST_TT_AUX_BOOL_TRAIT_DEF2( 206 is_base_and_derived 207 , Base 208 , Derived 209 , (::boost::detail::is_base_and_derived_impl<Base,Derived>::value) 210 ) 211 212 #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION 213 BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_2(typename Base,typename Derived,is_base_and_derived,Base&,Derived,false) 214 BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_2(typename Base,typename Derived,is_base_and_derived,Base,Derived&,false) 215 BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_2(typename Base,typename Derived,is_base_and_derived,Base&,Derived&,false) 216 #endif 217 218 } // namespace boost 219 220 #include "boost/type_traits/detail/bool_trait_undef.hpp" 221 222 #endif // BOOST_TT_IS_BASE_AND_DERIVED_HPP_INCLUDED 223