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
24namespace boost {
25
26namespace 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
40This version detects ambiguous base classes and private base classes
41correctly, and was devised by Rani Sharoni.
42
43Explanation by Terje Slettebo and Rani Sharoni.
44
45Let's take the multiple base class below as an example, and the following
46will also show why there's not a problem with private or ambiguous base
47class:
48
49struct B {};
50struct B1 : B {};
51struct B2 : B {};
52struct D : private B1, private B2 {};
53
54is_base_and_derived<B, D>::value;
55
56First, some terminology:
57
58SC - Standard conversion
59UDC - User-defined conversion
60
61A user-defined conversion sequence consists of an SC, followed by an UDC,
62followed by another SC. Either SC may be the identity conversion.
63
64When passing the default-constructed Host object to the overloaded check_sig()
65functions (initialization 8.5/14/4/3), we have several viable implicit
66conversion sequences:
67
68For "static no_type check_sig(B const volatile *, int)" we have the conversion
69sequences:
70
71C -> C const (SC - Qualification Adjustment) -> B const volatile* (UDC)
72C -> D const volatile* (UDC) -> B1 const volatile* / B2 const volatile* ->
73 B const volatile* (SC - Conversion)
74
75For "static yes_type check_sig(D const volatile *, T)" we have the conversion
76sequence:
77
78C -> D const volatile* (UDC)
79
80According to 13.3.3.1/4, in context of user-defined conversion only the
81standard conversion sequence is considered when selecting the best viable
82function, so it only considers up to the user-defined conversion. For the
83first function this means choosing between C -> C const and C -> C, and it
84chooses the latter, because it's a proper subset (13.3.3.2/3/2) of the
85former. Therefore, we have:
86
87C -> D const volatile* (UDC) -> B1 const volatile* / B2 const volatile* ->
88 B const volatile* (SC - Conversion)
89C -> D const volatile* (UDC)
90
91Here, the principle of the "shortest subsequence" applies again, and it
92chooses C -> D const volatile*. This shows that it doesn't even need to
93consider the multiple paths to B, or accessibility, as that possibility is
94eliminated before it could possibly cause ambiguity or access violation.
95
96If D is not derived from B, it has to choose between C -> C const -> B const
97volatile* for the first function, and C -> D const volatile* for the second
98function, which are just as good (both requires a UDC, 13.3.3.2), had it not
99been for the fact that "static no_type check_sig(B const volatile *, int)" is
100not templated, which makes C -> C const -> B const volatile* the best choice
101(13.3.3/1/4), resulting in "no".
102
103Also, if Host::operator B const volatile* hadn't been const, the two
104conversion sequences for "static no_type check_sig(B const volatile *, int)", in
105the case where D is derived from B, would have been ambiguous.
106
107See also
108http://groups.google.com/groups?selm=df893da6.0301280859.522081f7%40posting.
109google.com and links therein.
110
111*************************************************************************/
112
113template <typename B, typename D>
114struct 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
131template<typename B, typename D>
132struct 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//
167template<typename B, typename D>
168struct 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
178template <typename B, typename D>
179struct is_base_and_derived_impl3
180{
181 BOOST_STATIC_CONSTANT(bool, value = false);
182};
183
184template <bool ic1, bool ic2, bool iss>
185struct 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
194template <>
195struct 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
204template <typename B, typename D>
205struct 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
220template <typename B, typename D>
221struct 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
231template <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
234template <class Base, class Derived> struct is_base_and_derived<Base&, Derived> : public false_type{};
235template <class Base, class Derived> struct is_base_and_derived<Base, Derived&> : public false_type{};
236template <class Base, class Derived> struct is_base_and_derived<Base&, Derived&> : public false_type{};
237
238#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610))
239template <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

source code of boost/boost/type_traits/is_base_and_derived.hpp