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