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