Boost logo

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