>From: "Terje Slettebų" <[EMAIL PROTECTED]> > >From: "Rani Sharoni" <[EMAIL PROTECTED]> > > > Before changing the documentation please consider the following improved > > implemetation that overcomes ambiguity and access control issues of the > > current is_base_and_derived implemetation (I lately posted it to > c.l.c++.m) > > : > > > > template <typename B, typename D> > > struct is_base_and_derived > > { > > private: > > typedef char (&yes)[1]; > > typedef char (&no) [2]; > > > > template<typename T> > > static yes check(D const volatile &, T); > > static no check(B const volatile &, int); > > > > struct C > > { > > operator B const volatile &() const; > > operator D const volatile &(); > > }; > > > > static C getC(); > > public: > > static const bool result = > > sizeof(check(getC(), 0)) == sizeof(yes); > > }; > > > > Additional specializations needed (e.g. void and reference types) > > Very nice, Rani. Very clever. :) > > It's interesting that, according to your clc++m posting, the inspiration of > this came from Andrei Alexandrescu's article on Mojo, who also came up with > Loki's SuperSubclass trait. Dave Abrahams is also credited in the thread, > for contributing to the above technique.
The technique the above is based on is also very clever, of course. :) > As I understand, the reason it works for multiple occurrences of the same > base class is that it's not asking for D's B subobject, but instead for a > conversion to _a_ B (any B). After I sent this I came to wonder how this works, after all, and I found that the actual conversion done is C to D, not D to B, but the end result is that it means D is derived from B. In the previous posting, I didn't want to repeat the explanation given in the Vandevoorde posting that Rani gives link to in the clc++m posting (http://groups.google.com/groups?selm=df893da6.0301280859.522081f7%40posting .google.com). However, as Rani's code uses the technique there, with a few twists, I thought it could be useful to give a better explanation of its workings than my previous posting (which was mostly a sketch, to not repeat the mentioned posting, but thanks for the acknowledgement, Dave A.). So here goes: Let's take the multiple base class mentioned above, as an example, and the following will also show why there's not a problem with ambiguous base class: struct B {}; struct B1 : B {}; struct B2 : B {}; struct D : B1, private B2 {}; typedef char Test[is_base_and_derived<B, D>::result]; // improvement 1 - multiple base We have several possible conversion sequences: For "static no 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 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 -> B1/B2 -> B C -> D 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. :) 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". 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. Regards, Terje _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost