Click here to Skip to main content
6,630,586 members and growing! (15,612 online)
Email Password   helpLost your password?
Development Lifecycle » Design and Architecture » Data Structures     Advanced

Union Lists: Single Value, Multiple Types

By Christopher Diggins

A 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
Posted:4 Jan 2005
Updated:20 Jan 2005
Views:36,563
Bookmarked:21 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
14 votes for this article.
Popularity: 4.86 Rating: 4.24 out of 5
1 vote, 7.1%
1

2

3
3 votes, 21.4%
4
10 votes, 71.4%
5

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

About the Author

Christopher Diggins


Member
  I've been programming personal computers since my I got my first Atari 400 in 1980. I am currently self-employed as a consultant and author.

  I've worked as a professional programmer for over 12 years. I have written for Doctor Dobbs Journal, and C++ Users Journal. I also contributed to the C++ Cookbook released by O'Reilly.

  My area of research is the design and implementation of programming languages. My current project is the Cat programming language which is a cross between Forth and Haskell.
Occupation: Web Developer
Location: Canada Canada

Other popular Design and Architecture articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 18 of 18 (Total in Forum: 18) (Refresh)FirstPrevNext
GeneralElegant [modified] PinmemberPlaceboZA4:43 4 Sep '06  
GeneralProblem with typelist recursion PinmemberHades_G4:32 20 Jan '05  
GeneralRe: Problem with typelist recursion PinmemberChristopher Diggins6:29 20 Jan '05  
Generallooks similar with Loki's TypeList Pinmemberchenlee16:02 16 Jan '05  
Generalul_end is not defined PinmemberHans8:23 14 Jan '05  
GeneralRe: ul_end is not defined PinmemberHades_G5:15 20 Jan '05  
GeneralRe: ul_end is not defined PinmemberChristopher Diggins6:30 20 Jan '05  
GeneralINTERNAL COMPILER ERROR !!! PinmemberMohammed Hossny7:28 13 Jan '05  
GeneralRe: INTERNAL COMPILER ERROR !!! PinmemberChristopher Diggins6:30 20 Jan '05  
GeneralThis is interesting !! PinmemberWREY11:54 8 Jan '05  
GeneralRe: This is interesting !! PinmemberChristopher Diggins6:46 20 Jan '05  
GeneralVery Nice!! PinmemberWREY10:41 20 Jan '05  
GeneralDo you have an idea... Pinsupporterpeterchen15:06 4 Jan '05  
GeneralRe: Do you have an idea... Pinmembercdiggins18:33 4 Jan '05  
GeneralRe: Do you have an idea... PinmemberNemanja Trifunovic8:56 21 Jan '05  
GeneralRe: Do you have an idea... Pinmember.:floyd:.14:07 22 Jan '05  
GeneralVery good PinmemberFlorian Heidenreich11:56 4 Jan '05  
GeneralRe: Very good Pinmembercdiggins14:34 4 Jan '05  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin 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