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