|
Boost : |
From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2002-04-13 16:08:36
> We've talked about adding a switch-on-type construct for a while, so I
> thought I'd whip up a prototype that we could talk about. The prototype is
> here, but read on:
> http://groups.yahoo.com/group/boost/files/typeswitch-20020413.tgz
How about this for a *fun* intrusive switch-on-type? Note that I'm using some
Loki-like typelist facilities:
// selfish:
// implements a self thrower, this is the intrusive part
// note: for brevity, I have excluded pass-through constructors
// (this class is intended as a base class)
// also note that this class is not necessary,
// it just implements 'self' for you.
template<class sub, class super = void>
struct selfish;
// specialization for no base class
template<class sub>
struct selfish<sub, void> {
virtual void self(void) {
throw static_cast<sub*>(this);
}
};
// general template
template<class sub, class super>
struct selfish : public super {
virtual void self(void) {
throw static_cast<sub*>(this);
}
};
struct unknown_type { }; // error type to throw
// polymorph_impl
// implements a exception frames recursively
template<class TL, template<class> class T>
struct polymorph_impl;
// terminating condition...
template<class head, template<class> class T>
struct polymorph_impl<typelist_t<head, null_t>, T> {
template<class U>
static typename T<head>::result_t exec(U& ref)
{
try {
ref.self();
}
catch (head* ps) {
return T<head>::exec(*ps);
}
throw unknown_type(); // should never get here
}
};
// general template
template<class head, class tail, template<class> class T>
struct polymorph_impl<typelist_t<head, tail>, T> {
template<class U>
static typename T<head>::result_t exec(U& ref)
{
try {
return polymorph_impl<tail, T>::exec(ref);
}
catch (head* ps) {
return T<head>::exec(*ps);
}
}
};
// polymorph
// this is the front end, it reorders the typelist to make
// sure that no unintended implicit conversion is performed.
// it also maps any other exception types (T*) to an unknown_type
// exception
template<class TL, template<class> class T>
struct polymorph;
template<class head, class tail, template<class> class T>
struct polymorph<typelist_t<head, tail>, T> {
template<class U>
static typename T<head>::result_t exec(U& ref)
{
try {
typedef typename
derived_to_back<typelist_t<head, tail> >::type
// ^ back not front :)
reordered;
return polymorph_impl<reordered, T>::exec(ref);
}
catch (...) {
throw unknown_type(); // this might happen
}
}
};
// sample classes, these classes have a non-virtual function
// that returns the name of the class.
// sample hierarchy #1
struct X : selfish<X> {
const char* name() const {
return "struct X";
}
};
struct Y : selfish<Y, X> {
const char* name() const {
return "struct Y";
}
};
struct Z : selfish<Z, Y> {
const char* name() const {
return "struct Z";
}
};
// sample hierarchy #2
struct A : selfish<A> {
const char* name() const {
return "struct A";
}
};
struct B : selfish<B, A> {
const char* name() const {
return "struct B";
}
};
// name:
// this class basically re-maps the name
// of the member function to call
template<class T> struct name {
typedef const char* result_t;
static inline result_t exec(T& ref) {
return ref.name();
}
};
// usage:
int main() {
typedef polymorph<TYPELIST_5(Z, X, Y, B, A), name> polyname;
Y y;
A a;
std::cout
<< polyname::exec(a) << '\n'
<< polyname::exec(y) << &std::endl;
return 0;
}
How's that for a gross misuse of the exception handling mechanism? --but fun
none the less :)
Paul Mensonides
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk