Click here to Skip to main content
Click here to Skip to main content

Union Lists: Single Value, Multiple Types

, 20 Jan 2005
Rate this:
Please Sign up or sign in to vote.
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 <span class="code-keyword"><string>
</span>
#include <span class="code-keyword"><iostream>
</span>

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

Share

About the Author

Christopher Diggins
Software Developer Autodesk
Canada Canada
This article was written by Christopher Diggins, a computer science nerd who currently works at Autodesk as an SDK specialist.
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
GeneralElegant [modified] PinmemberPlaceboZA4-Sep-06 4:43 
GeneralProblem with typelist recursion PinmemberHades_G20-Jan-05 4:32 
GeneralRe: Problem with typelist recursion PinmemberChristopher Diggins20-Jan-05 6:29 
Generallooks similar with Loki's TypeList Pinmemberchenlee16-Jan-05 16:02 
Generalul_end is not defined PinmemberHans14-Jan-05 8:23 
GeneralRe: ul_end is not defined PinmemberHades_G20-Jan-05 5:15 
GeneralRe: ul_end is not defined PinmemberChristopher Diggins20-Jan-05 6:30 
GeneralINTERNAL COMPILER ERROR !!! PinmemberMohammed Hossny13-Jan-05 7:28 
GeneralRe: INTERNAL COMPILER ERROR !!! PinmemberChristopher Diggins20-Jan-05 6:30 
GeneralThis is interesting !! PinmemberWREY8-Jan-05 11:54 
GeneralRe: This is interesting !! PinmemberChristopher Diggins20-Jan-05 6:46 
GeneralVery Nice!! PinmemberWREY20-Jan-05 10:41 
GeneralDo you have an idea... Pinmemberpeterchen4-Jan-05 15:06 
GeneralRe: Do you have an idea... Pinmembercdiggins4-Jan-05 18:33 
GeneralRe: Do you have an idea... PinmemberNemanja Trifunovic21-Jan-05 8:56 
GeneralRe: Do you have an idea... Pinmember.:floyd:.22-Jan-05 14:07 
GeneralVery good PinmemberFlorian Heidenreich4-Jan-05 11:56 
GeneralRe: Very good Pinmembercdiggins4-Jan-05 14:34 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141223.1 | Last Updated 20 Jan 2005
Article Copyright 2005 by Christopher Diggins
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid