diff --git a/include/boost/type_traits/is_base_and_derived.hpp b/include/boost/type_traits/is_base_and_derived.hpp index 6b5eb58..fec3075 100644 --- a/include/boost/type_traits/is_base_and_derived.hpp +++ b/include/boost/type_traits/is_base_and_derived.hpp @@ -1,5 +1,5 @@ -// (C) Copyright Rani Sharoni 2002. +// (C) Copyright Rani Sharoni 2003. // Permission to copy, use, modify, sell and distribute this software is // granted provided this copyright notice appears in all copies. This software // is provided "as is" without express or implied warranty, and with no claim @@ -35,58 +35,73 @@ namespace detail { This version detects ambiguous base classes and private base classes correctly, and was devised by Rani Sharoni. -The following explanation is by Terje Slettebo: +Explanation by Terje Slettebų and Rani Sharoni. -Let's take the multiple base class below as an example, and the -following will also show why there's not a problem with ambiguous base +Let's take the multiple base class below as an example, and the following +will also show why there's not a problem with private or ambiguous base class: struct B {}; struct B1 : B {}; struct B2 : B {}; -struct D : B1, private B2 {}; +struct D : private B1, private B2 {}; -typedef char Test[is_base_and_derived::result]; // improvement 1 - -multiple base +is_base_and_derived::value; +First, some terminology: -We have several possible conversion sequences: +SC - Standard conversion +UDC - User-defined conversion -For "static no check(B const volatile *, int)" we have the conversion +A user-defined conversion sequence consists of an SC, followed by an UDC, +followed by another SC. Either SC may be the identity conversion. + +When passing the default-constructed Host object to the overloaded check() +functions (initialization 8.5/14/4/3), we have several viable implicit +conversion sequences: + +For "static no_type check(B const volatile *, int)" we have the conversion sequences: - C -> C const -> B* -and - C -> D* -> B1*|B2* -> B* -For "static yes check(D const volatile *, T)" we have the conversion +C -> C const (SC - Qualification Adjustment) -> B const volatile* (UDC) +C -> D const volatile* (UDC) -> B1 const volatile*/B2 const volatile* -> + B const volatile* (SC - Conversion) + +For "static yes_type check(D const volatile *, T)" we have the conversion sequence: - C -> D* -Since, for the purpose of selecting the appropriate user-defined conversion -for a given function, it only considers up to the user-defined conversion, -for the first function this means choosing between C -> C const and C -> C, -and it chooses the latter. Therefore, we have: +C -> D const volatile* (UDC) -C -> D* -> B1*|B2* -> B* -C -> D* +According to 13.3.3.1/4, in context of user-defined conversion only the +standard conversion sequence is considered when selecting the best viable +function, so it only considers up to the user-defined conversion. For the +first function this means choosing between C -> C const and C -> C, and it +chooses the latter, because it's a proper subset (13.3.3.2/3/2) of the +former. Therefore, we have: -Here, the principle of the "shortest subsequence" applies, and it chooses -C -> D*. This shows that it doesn't even need to consider the multiple paths -to B, as that possibility is eliminated before it could possibly cause -ambiguity. Nifty. :) +C -> D const volatile* (UDC) -> B1 const volatile*/B2 const volatile* -> + B const volatile* (SC - Conversion) +C -> D const volatile* (UDC) -As Daveed notes in the posting Rani gives a link to in the clc++m posting, -if D is not derived from B, it has to choose between C -> C const -> B* for -the first function, and C -> D* for the second function, which are just as -good, _had it not been for the fact that "static no check(B const volatile -&, int)" is not templated (as Rani points out in the posting)_, which makes -C -> C const -> B* the best choice, resulting in "no". +Here, the principle of the "shortest subsequence" applies again, and it +chooses C -> D const volatile*. This shows that it doesn't even need to +consider the multiple paths to B, or accessibility, as that possibility is +eliminated before it could possibly cause ambiguity or access violation. -Also, if C::operator B* hadn't been const, the two conversion sequences for -"static no check(B const volatile *, int)" would have been ambiguous. +If D is not derived from B, it has to choose between C -> C const -> B const +volatile* for the first function, and C -> D const volatile* for the second +function, which are just as good (both requires a UDC, 13.3.3.2), had it not +been for the fact that "static no_type check(B const volatile *, int)" is +not templated, which makes C -> C const -> B const volatile* the best choice +(13.3.3/1/4), resulting in "no". -See also http://groups.google.com/groups?selm=df893da6.0301280859.522081f7%40posting.google.com -and links therein. +Also, if Host::operator B const volatile* hadn't been const, the two +conversion sequences for "static no_type check(B const volatile *, int)", in +the case where D is derived from B, would have been ambiguous. + +See also +http://groups.google.com/groups?selm=df893da6.0301280859.522081f7%40posting. +google.com and links therein. *************************************************************************/ @@ -189,5 +204,3 @@ BOOST_TT_AUX_BOOL_TRAIT_PARTIAL_SPEC2_2(typename Base,typename Derived,is_base_a #include "boost/type_traits/detail/bool_trait_undef.hpp" #endif // BOOST_TT_IS_BASE_AND_DERIVED_HPP_INCLUDED - -