2 // (C) Copyright Rani Sharoni 2003.
3 // Permission to copy, use, modify, sell and distribute this software is
4 // granted provided this copyright notice appears in all copies. This software
5 // is provided "as is" without express or implied warranty, and with no claim
6 // as to its suitability for any purpose.
8 // See http://www.boost.org for most recent version including documentation.
10 #ifndef BOOST_TT_IS_BASE_AND_DERIVED_HPP_INCLUDED
11 #define BOOST_TT_IS_BASE_AND_DERIVED_HPP_INCLUDED
13 #include "boost/type_traits/is_class.hpp"
14 #include "boost/type_traits/is_same.hpp"
15 #include "boost/type_traits/is_convertible.hpp"
16 #include "boost/type_traits/detail/ice_and.hpp"
17 #include "boost/type_traits/remove_cv.hpp"
18 #include "boost/config.hpp"
20 // should be the last #include
21 #include "boost/type_traits/detail/bool_trait_def.hpp"
27 #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x570)) \
28 && !BOOST_WORKAROUND(__SUNPRO_CC , BOOST_TESTED_AT(0x540)) \
29 && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238)
30 // The EDG version number is a lower estimate.
31 // It is not currently known which EDG version
32 // exactly fixes the problem.
34 /*************************************************************************
36 This version detects ambiguous base classes and private base classes
37 correctly, and was devised by Rani Sharoni.
39 Explanation by Terje Slettebø and Rani Sharoni.
41 Let's take the multiple base class below as an example, and the following
42 will also show why there's not a problem with private or ambiguous base
48 struct D : private B1, private B2 {};
50 is_base_and_derived<B, D>::value;
52 First, some terminology:
54 SC - Standard conversion
55 UDC - User-defined conversion
57 A user-defined conversion sequence consists of an SC, followed by an UDC,
58 followed by another SC. Either SC may be the identity conversion.
60 When passing the default-constructed Host object to the overloaded check()
61 functions (initialization 8.5/14/4/3), we have several viable implicit
64 For "static no_type check(B const volatile *, int)" we have the conversion
67 C -> C const (SC - Qualification Adjustment) -> B const volatile* (UDC)
68 C -> D const volatile* (UDC) -> B1 const volatile* / B2 const volatile* ->
69 B const volatile* (SC - Conversion)
71 For "static yes_type check(D const volatile *, T)" we have the conversion
74 C -> D const volatile* (UDC)
76 According to 13.3.3.1/4, in context of user-defined conversion only the
77 standard conversion sequence is considered when selecting the best viable
78 function, so it only considers up to the user-defined conversion. For the
79 first function this means choosing between C -> C const and C -> C, and it
80 chooses the latter, because it's a proper subset (13.3.3.2/3/2) of the
81 former. Therefore, we have:
83 C -> D const volatile* (UDC) -> B1 const volatile* / B2 const volatile* ->
84 B const volatile* (SC - Conversion)
85 C -> D const volatile* (UDC)
87 Here, the principle of the "shortest subsequence" applies again, and it
88 chooses C -> D const volatile*. This shows that it doesn't even need to
89 consider the multiple paths to B, or accessibility, as that possibility is
90 eliminated before it could possibly cause ambiguity or access violation.
92 If D is not derived from B, it has to choose between C -> C const -> B const
93 volatile* for the first function, and C -> D const volatile* for the second
94 function, which are just as good (both requires a UDC, 13.3.3.2), had it not
95 been for the fact that "static no_type check(B const volatile *, int)" is
96 not templated, which makes C -> C const -> B const volatile* the best choice
97 (13.3.3/1/4), resulting in "no".
99 Also, if Host::operator B const volatile* hadn't been const, the two
100 conversion sequences for "static no_type check(B const volatile *, int)", in
101 the case where D is derived from B, would have been ambiguous.
104 http://groups.google.com/groups?selm=df893da6.0301280859.522081f7%40posting.
105 google.com and links therein.
107 *************************************************************************/
109 template <typename B, typename D>
112 template <typename T>
113 static type_traits::yes_type check(D const volatile *, T);
114 static type_traits::no_type check(B const volatile *, int);
117 template<typename B, typename D>
118 struct is_base_and_derived_impl2
122 operator B const volatile *() const;
123 operator D const volatile *();
126 BOOST_STATIC_CONSTANT(bool, value =
127 sizeof(bd_helper<B,D>::check(Host(), 0)) == sizeof(type_traits::yes_type));
135 template<typename B, typename D>
136 struct is_base_and_derived_impl2
138 BOOST_STATIC_CONSTANT(bool, value =
139 (::boost::is_convertible<D*,B*>::value));
142 #define BOOST_BROKEN_IS_BASE_AND_DERIVED
146 template <typename B, typename D>
147 struct is_base_and_derived_impl3
149 BOOST_STATIC_CONSTANT(bool, value = false);
152 template <bool ic1, bool ic2, bool iss>
153 struct is_base_and_derived_select
155 template <class T, class U>
158 typedef is_base_and_derived_impl3<T,U> type;
163 struct is_base_and_derived_select<true,true,false>
165 template <class T, class U>
168 typedef is_base_and_derived_impl2<T,U> type;
172 template <typename B, typename D>
173 struct is_base_and_derived_impl
175 typedef typename remove_cv<B>::type ncvB;
176 typedef typename remove_cv<D>::type ncvD;
178 typedef is_base_and_derived_select<
179 ::boost::is_class<B>::value,
180 ::boost::is_class<D>::value,
181 ::boost::is_same<B,D>::value> selector;
182 typedef typename selector::template rebind<ncvB,ncvD> binder;
183 typedef typename binder::type bound_type;
185 BOOST_STATIC_CONSTANT(bool, value = bound_type::value);
188 } // namespace detail
190 BOOST_TT_AUX_BOOL_TRAIT_DEF2(
194 , (::boost::detail::is_base_and_derived_impl<Base,Derived>::value)
197 #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
198 BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_2(typename Base,typename Derived,is_base_and_derived,Base&,Derived,false)
199 BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_2(typename Base,typename Derived,is_base_and_derived,Base,Derived&,false)
200 BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_2(typename Base,typename Derived,is_base_and_derived,Base&,Derived&,false)
205 #include "boost/type_traits/detail/bool_trait_undef.hpp"
207 #endif // BOOST_TT_IS_BASE_AND_DERIVED_HPP_INCLUDED