I implemented a "discriminated union" capable of holding C++ types, even if they have destructors etc. I implemented this as a Russian doll; i.e. Union<T1, T2, T3>
derives from unionNode<T1, <UnionNode<T2, UnionNode<T3, void> > >
and UnionNode<T, Tail>
derives from Tail. The specialization UnionNode<T, void>
holds a void* which contains the actual data, and an index to store the current type.
For quite a few functions, I'd like a meta-function to determine if a type U is one of the types T1..Tn
. For instance, I've got a member template<typename U> union_cast<U>
that should only be instantiated for types that could actually be in the union. Trying to cast a Union to std::string is a compile-time error.
The simple solution was to add a template <typename U> struct inUnion
:
template <typename T, typename Tail> // Tail will be a UnionNode too.
struct UnionNode : public Tail {
// ...
template<typename U> struct inUnion {
typedef Tail::inUnion<U> dummy; // <<< Q: where to add typename/template here?
};
template< > struct inUnion<T> {
};
};
template <typename T> // For the last node Tn.
struct UnionNode<T, void> {
// ...
template<typename U> struct inUnion {
char fail[ -sizeof(U) ]; // Cannot be instantiated for any U
};
template< > struct inUnion<T> {
};
};
The idea is simple, I think: Each UnionNode<T, Tail>
defines a template specialization inUnion<T>
, and forwards the generic case inUnion<U>
. If in the last node, no specialization of inUnion<U>
has been found, then U is not one of the types T1...Tn
, and I try to typedef an array with negative size. The problem I have is in the typedef Tail::inUnion<U> dummy
line. I'm fairly certain that inUnion is a dependent name, and VC++ is quite right in choking on it. I also know that I should be able to add "template" somewhere to tell the compiler that inUnion is a template-id. But where exactly? And should it then assume that inUnion is a class template, i.e. inUnion<U>
names a type and not a function?