template<typename Target, typename Excluding, typename Source>
struct exclusive_cast {
static Target* cast(Source *s) {
if( ! dynamic_cast<Excluding *>(s) ) {
return dynamic_cast<Target *>(s);
}
return NULL;
}
};
template<typename Ex1, typename Ex2>
struct ExcludingBoth {};
template<typename Target, typename Ex1, typename Ex2, typename Source>
struct exclusive_cast<Target, ExcludingBoth<Ex1, Ex2>, Source> {
static Target* cast(Source *s) {
if( ! dynamic_cast<Ex1 *>( s ) ) {
return exclusive_cast<Target, Ex2, Source>::cast(s);
}
return NULL;
}
};
That was the header, exclusive_cast.hpp. Now here's a little test program that makes sure it does what I think it does:
#include <iostream>
#include "exclusive_cast.hpp"
class A {
virtual void rtti_rules() {}
};
class B : public A {};
class C : public B {};
class D : public B {};
class E : public B {};
int main() {
B b;
C c;
D d;
E e;
A *ab = &b;
A *ac = &c;
A *ad = &d;
A *ae = &e;
if( exclusive_cast<B, C, A>::cast(ab) ) {
std::cout << "correct" << std::endl;
} else {
std::cout << "incorrect" << std::endl;
}
if( exclusive_cast<B, C, A>::cast(ac) ) {
std::cout << "incorrect" << std::endl;
} else {
std::cout << "correct" << std::endl;
}
if( exclusive_cast<B, ExcludingBoth<C, D>, A>::cast(ad) ) {
std::cout << "incorrect" << std::endl;
} else {
std::cout << "correct" << std::endl;
}
typedef exclusive_cast<B, ExcludingBoth<C, ExcludingBoth<D, E> >, A> complicated;
if( complicated::cast(ae) ) {
std::cout << "incorrect" << std::endl;
} else {
std::cout << "correct" << std::endl;
}
if( complicated::cast(ad) ) {
std::cout << "incorrect" << std::endl;
} else {
std::cout << "correct" << std::endl;
}
if( complicated::cast(ac) ) {
std::cout << "incorrect" << std::endl;
} else {
std::cout << "correct" << std::endl;
}
if( complicated::cast(ab) ) {
std::cout << "correct" << std::endl;
} else {
std::cout << "incorrect" << std::endl;
}
return 0;
}
A possible improvement might be to nest the template parameter Source inside the struct for the cast function so wouldn't need to name Source necessarily.