![]() |
Development Lifecycle »
Design and Architecture »
Data Structures
Advanced
Union Lists: Single Value, Multiple TypesBy Christopher DigginsA union list is a simple union style type which can hold one value of any of a fixed number of types. |
C++, Windows, Visual Studio, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
A union list ( ul ) is a polymorphic type that can hold one value from one of the predetermined set of types. The precise type that a union list represents is determined at run-time when constructed based on the type of the value it is initialized with.
The primary role of a union list is to allow polymorphism between completely unrelated types. Unions have too many unreasonable limitations to be useful in most situations.
A union list is declared recursively as follows:
ul<int, ul<char const*, ul_end> >
Note that the last element has to be of type ul_end. Usually we would use a union list with a typedef to save typing:
typedef ul<int, ul<char const*, ul_end> > IntOrString_T;
Declaring a variable of type ul requires an initializing value, such as:
IntOrString_T i(42); IntOrString_T s("hello");
Once a ul is constructed, it provides the index of the type that it represents.
cout << i.TypeIndex() << endl; // outputs 0 cout << s.TypeIndex() << endl; // outputs 1
Of course, what is most important is accessing the data. This is done by passing the index of the type as a template parameter:
cout << i.Get<0>() << endl; // outputs 42 cout << s.Get<1>() << endl; // outputs "hello"
Of course, it can be a bit tricky to always correctly match the index passed to Get() with the correct internal data index, but don't worry, the union list will throw an exception if you make a mistake:
cout << i.Get<1>() << endl; // throws an exception
Here is the entire source code for the union list:
// public domain by Christopher Diggins, January 2005 // // This is a utility class which allows the user to define a // union of an arbitrary number of a list of types
struct ul_end { const TypeIndex() { return 0; } };
template<typename Head_T, typename Tail_T, int N> struct TypeList { typedef typename TypeList< typename Tail_T::H_T, typename Tail_T::T_T, N - 1>::type type; };
template<typename Head_T, typename Tail_T> struct TypeList<Head_T, Tail_T, 0> { typedef typename Head_T type; };
template<typename Head_T, typename Tail_T> struct ul { typedef typename ul<Head_T, Tail_T> self; template<typename T> ul(T x) : tail(x), tag(false) { } template<> ul(Head_T x) : head(x), tag(true) { } ul(const self& x) : head(x.head), tail(x.tail), tag(x.tag) { } ul() { }; typedef typename Head_T H_T; typedef typename Tail_T T_T; Head_T head; Tail_T tail; bool tag; template<int N> typename TypeList<Head_T, Tail_T, N>::type& Get() { if (N != TypeIndex()) { throw 0; } return *(TypeList<Head_T, Tail_T, N>::type*)InternalGet<N>(); };
template<int N> void* InternalGet() { return tail.InternalGet<N-1>(); };
template<> void* InternalGet<0>() { return &head; };
const int TypeIndex() { return tag ? 0 : tail.TypeIndex() + 1; } };
Here is some example code to get you going:
#include <string> #include <iostream> using namespace std;
typedef ul< int, ul< char, ul< bool, ul< double, ul< string, ul_end > > > > > test_type;
void output(test_type x) { switch(x.TypeIndex()) { case 0 : cout << "int : " << x.Get<0>() << endl; break; case 1 : cout << "char : " << x.Get<1>() << endl; break; case 2 : cout << "bool : " << x.Get<2>() << endl; break; case 3 : cout << "float : " << x.Get<3>() << endl; break; case 4 : cout << "string : " << x.Get<4>() << endl; break; } }
int main() { output('a'); output(3.141); output(42); output(string("Hello world")); output(true); getchar(); return 0; }
It would be preferable to have the TypeList type as a member template, as it would save a lot of scaffolding code, but unfortunately that is not portable across platforms. Member type template specializations are not part of the standard for some obscure reason.
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 20 Jan 2005 Editor: Sumalatha K.R. |
Copyright 2005 by Christopher Diggins Everything else Copyright © CodeProject, 1999-2009 Web09 | Advertise on the Code Project |