Click here to Skip to main content
15,867,297 members
Articles / Programming Languages / C++
Article

Union Lists: Single Value, Multiple Types

Rate me:
Please Sign up or sign in to vote.
4.63/5 (16 votes)
20 Jan 20051 min read 66.9K   28   19
A union list is a simple union style type which can hold one value of any of a fixed number of types.

Introduction

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.

Motivation

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.

Using a Union List

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

The Code

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;
}

Postscript

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer Ara 3D
Canada Canada
I am the designer of the Plato programming language and I am the founder of Ara 3D. I can be reached via email at cdiggins@gmail.com

Comments and Discussions

 
Questiongreat code Pin
Martial Spirit18-Mar-16 20:45
Martial Spirit18-Mar-16 20:45 
GeneralElegant [modified] Pin
PlaceboZA4-Sep-06 3:43
PlaceboZA4-Sep-06 3:43 
GeneralProblem with typelist recursion Pin
Hades_G20-Jan-05 3:32
Hades_G20-Jan-05 3:32 
GeneralRe: Problem with typelist recursion Pin
Christopher Diggins20-Jan-05 5:29
professionalChristopher Diggins20-Jan-05 5:29 
Generallooks similar with Loki's TypeList Pin
chenlee16-Jan-05 15:02
chenlee16-Jan-05 15:02 
Generalul_end is not defined Pin
Hans14-Jan-05 7:23
Hans14-Jan-05 7:23 
I can't get this working because ul_end is not defined. As this is heavy template stuff I have no idea how this should be defined. As I like your idea I would be very interested in complete code. My environment is VS2003. Thank you in advance.

Hans
GeneralRe: ul_end is not defined Pin
Hades_G20-Jan-05 4:15
Hades_G20-Jan-05 4:15 
GeneralRe: ul_end is not defined Pin
Christopher Diggins20-Jan-05 5:30
professionalChristopher Diggins20-Jan-05 5:30 
GeneralINTERNAL COMPILER ERROR !!! Pin
Mo Hossny13-Jan-05 6:28
Mo Hossny13-Jan-05 6:28 
GeneralRe: INTERNAL COMPILER ERROR !!! Pin
Christopher Diggins20-Jan-05 5:30
professionalChristopher Diggins20-Jan-05 5:30 
GeneralThis is interesting !! Pin
WREY8-Jan-05 10:54
WREY8-Jan-05 10:54 
GeneralRe: This is interesting !! Pin
Christopher Diggins20-Jan-05 5:46
professionalChristopher Diggins20-Jan-05 5:46 
GeneralVery Nice!! Pin
WREY20-Jan-05 9:41
WREY20-Jan-05 9:41 
GeneralDo you have an idea... Pin
peterchen4-Jan-05 14:06
peterchen4-Jan-05 14:06 
GeneralRe: Do you have an idea... Pin
Christopher Diggins4-Jan-05 17:33
professionalChristopher Diggins4-Jan-05 17:33 
GeneralRe: Do you have an idea... Pin
Nemanja Trifunovic21-Jan-05 7:56
Nemanja Trifunovic21-Jan-05 7:56 
GeneralRe: Do you have an idea... Pin
.:floyd:.22-Jan-05 13:07
.:floyd:.22-Jan-05 13:07 
GeneralVery good Pin
Florian Heidenreich4-Jan-05 10:56
Florian Heidenreich4-Jan-05 10:56 
GeneralRe: Very good Pin
Christopher Diggins4-Jan-05 13:34
professionalChristopher Diggins4-Jan-05 13:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.