]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | |
20effc67 | 29 | #if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x581)) \ |
7c673cae FG |
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 | ||
20effc67 | 238 | #if BOOST_WORKAROUND(BOOST_CODEGEARC, BOOST_TESTED_AT(0x610)) |
7c673cae FG |
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 |