source: NonGTP/Boost/boost/type_traits/is_base_and_derived.hpp @ 857

Revision 857, 7.2 KB checked in by igarcia, 18 years ago (diff)
Line 
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
22namespace boost {
23
24namespace 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
37This version detects ambiguous base classes and private base classes
38correctly, and was devised by Rani Sharoni.
39
40Explanation by Terje Slettebø and Rani Sharoni.
41
42Let's take the multiple base class below as an example, and the following
43will also show why there's not a problem with private or ambiguous base
44class:
45
46struct B {};
47struct B1 : B {};
48struct B2 : B {};
49struct D : private B1, private B2 {};
50
51is_base_and_derived<B, D>::value;
52
53First, some terminology:
54
55SC  - Standard conversion
56UDC - User-defined conversion
57
58A user-defined conversion sequence consists of an SC, followed by an UDC,
59followed by another SC. Either SC may be the identity conversion.
60
61When passing the default-constructed Host object to the overloaded check_sig()
62functions (initialization 8.5/14/4/3), we have several viable implicit
63conversion sequences:
64
65For "static no_type check_sig(B const volatile *, int)" we have the conversion
66sequences:
67
68C -> C const (SC - Qualification Adjustment) -> B const volatile* (UDC)
69C -> D const volatile* (UDC) -> B1 const volatile* / B2 const volatile* ->
70     B const volatile* (SC - Conversion)
71
72For "static yes_type check_sig(D const volatile *, T)" we have the conversion
73sequence:
74
75C -> D const volatile* (UDC)
76
77According to 13.3.3.1/4, in context of user-defined conversion only the
78standard conversion sequence is considered when selecting the best viable
79function, so it only considers up to the user-defined conversion. For the
80first function this means choosing between C -> C const and C -> C, and it
81chooses the latter, because it's a proper subset (13.3.3.2/3/2) of the
82former. Therefore, we have:
83
84C -> D const volatile* (UDC) -> B1 const volatile* / B2 const volatile* ->
85     B const volatile* (SC - Conversion)
86C -> D const volatile* (UDC)
87
88Here, the principle of the "shortest subsequence" applies again, and it
89chooses C -> D const volatile*. This shows that it doesn't even need to
90consider the multiple paths to B, or accessibility, as that possibility is
91eliminated before it could possibly cause ambiguity or access violation.
92
93If D is not derived from B, it has to choose between C -> C const -> B const
94volatile* for the first function, and C -> D const volatile* for the second
95function, which are just as good (both requires a UDC, 13.3.3.2), had it not
96been for the fact that "static no_type check_sig(B const volatile *, int)" is
97not templated, which makes C -> C const -> B const volatile* the best choice
98(13.3.3/1/4), resulting in "no".
99
100Also, if Host::operator B const volatile* hadn't been const, the two
101conversion sequences for "static no_type check_sig(B const volatile *, int)", in
102the case where D is derived from B, would have been ambiguous.
103
104See also
105http://groups.google.com/groups?selm=df893da6.0301280859.522081f7%40posting.
106google.com and links therein.
107
108*************************************************************************/
109
110template <typename B, typename D>
111struct 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
128template<typename B, typename D>
129struct 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//
150template<typename B, typename D>
151struct 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
161template <typename B, typename D>
162struct is_base_and_derived_impl3
163{
164    BOOST_STATIC_CONSTANT(bool, value = false);
165};
166
167template <bool ic1, bool ic2, bool iss>
168struct 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
177template <>
178struct 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
187template <typename B, typename D>
188struct 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
205BOOST_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
213BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_2(typename Base,typename Derived,is_base_and_derived,Base&,Derived,false)
214BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_2(typename Base,typename Derived,is_base_and_derived,Base,Derived&,false)
215BOOST_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
Note: See TracBrowser for help on using the repository browser.