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