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 | |