Details

In this article, I originally wanted to talk about variant. variant is a very powerful template that allows you to create union-like data types that can contain C++ classes. As you all know in C++, it is not legal to have non-POD data types in union. For example the following code won't compile.

As I was writing about variant, I realized that it won't be complete without a description of typelists. So I decided to talk about typelists first. A great introduction to typelists could be found in the excellent book by A. Alexandrescu "Modern C++ Design". However our implementation of typelist is quite different from that described in the book. I believe that the suggested implementation is more efficient and easier to understand and debug.

Also please note that the code extracts in this article are to demonstrate the basic ideas only. The complete implementation could be found in TTL

What is typelist? Typelists are a compile time structures that are extremely important for generic and meta programming. Typelists provide a COMPILE TIME management of data types. They don't hold any user data nor do they have any run-time methods. ttl::meta::typelist in TTL is a foundation for ttl::var::variant.

The simplest typelist allows you to list your data types and have a compile-time access to its elements and other typelist properties such as the list length.

As follows from this example, our objective is toimplement following templates:

typelist<>
get<>
length<>

Implementation

The typelist implementation suggested in "Modern C++ Design" uses nested templates. Our implementation uses recursive types. According to "C++ Templates: Complete Guide" by David Vandevoorde and Nicolai Josuttis, recursive types put less stress on the compiler and from my experience, are easier for debugging.

typelist can contain a variable number of data types. Unfortunately C++ standard doesn't allow us to define a variable number of template parameters. We'll have to find a way to work around it. It is obvious that we'll need to put a hard limit on the maximal number of types in typelist. In TTL, the limit is defined in the config.h file the macro name is TTL_MAX_TEMPLATE_PARAMS. For the simplicity sake, we put the limit to 5. So the basic typelist definition will be as follows.

Note: by using the the default template parameter type empty, we can actually use typelist as a template with a variable number of template parameters up to 5.

typelist< int >,
typelist< int, double >
...

It is convenient to process lists recursively. A well known method is to use the head/tail idiom. First we want to find the length of the list. To do that we insert the length value in the typelist itself and define the first parameters as head and the rest as another typelist that is tail. In this case the typelist length is the tail length plus 1.

get<> is more interesting. It is obvious that it will have to be recursive. The recursion should stop when the index of the requested element is equal to the recursion step. If the index is bigger than the typelist's length, get<> should generate a compile-time error. First, let's make the basic definition.

The access time during compilation is O(N). TTL suggests an implementation that has a constant access time independent of the number of elements in the list. However it is not as elegant as this one.

Using the Code

The whole library resides in header files only. There is nothing to be built or installed, just copy the TTL files into one of you folders and and make sure that this folder is in the list of include folders in your compiler. You can then include TTL headers as in the following example.

#include"ttl/meta/typelist.hpp"

The source contains a simple sample in the samples/test folder. The code has been tested with MSVC v7.1 and GCC v3.2.3

Conclusion

C++ templates is a powerful mechanism for compile-time calculations and meta programming. The recursive instantiation and partial specialization are the corner stones of such methods. What I especially like about compile-time programming is that if the code compiles it usually runs right away. Well, almost...:)

If there is enough interest, in my next article, I'll describe how to implement and use variant. If you are interested, please vote.

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.

I've built a Parameter Map around ttl::variant that allows you to store/retrieve/serialize parameters of different types with a unified interface, useful for decoupling application code from UI (I have a binding for fltk).

Also I'm using a Parameter List based on variant to pass arguments to callbacks. You can do ParameterList::match(floatval, intval, boolval, myTypeObj) = failed_match_index, or ParameterList::get(f, i, b, mt) ect...not rocket science but if these are useful to anyone please let me know, I'll post them here

I built this stuff in less than a day due to the simplicity and power of variant! so thanks for the great article and code.

This can be useful when you want a generic callback ie func(const ParameterList &) that can take different parameters with some type saftey mechanism. Obvious applications in scripting and plug-in architectures where callbacks are used alot.

If this is useful to someone I'll post the source for the ParameterList class.

Faraz------------------------------------------Templates are good for you

1. It seems like match() is adding an unnecessary instantiation of default-constructible variables like int(), std::string(), etc (BTW: this requires that the types had a default c'tor).Have you considered something likematch < int, int, std::string > m(pl);int param_test = m.result;

2. Have you looked at ttl::tup::tuple?It seems like there are some similaritiesbetween tuples and your ParameterList?

ParameterList was designed to work at runtime - this allows it to be used to contain parameters parsed from a run-time script for example, or via callback, and adds flexibility when using late binding. This makes it less efficient than the compile-time equivalent tuple, but more flexible in these situations.

I'm having some difficulty making the constructor a func template. This seems to affect the ParameterList type, although ParameterList is not a template.struct ParameterList {template <t0, t1, t2> ParameterList(t0 p0, t1 p1, t2 p2) { insert(p0,p1,p2); };

Thank you for the clear introduction on typelists. The boost mpl macro mayhem is hard to decipher - I suspected that mpl typelists were based on default parameters, but that's as far as I got. Thankfully a quick google search led me here...

Problem 3List processing, Class, inheritance, polymorphismAssume that in Task 1 above, a linearly linked list is used to represent a set within a class. Re program both Task 1 and Task 2 where linearly linked list is used. You are required to specifically comment on the strengths or weaknesses of the two approaches taken in your documentation.

Problem 1 Array manipulations, Class, Exception, handling, Generic Class.Design, implement and test a set class in C++ that provides the operations; set membership, set intersection, set union and set difference. An array is to be used to represent a set within a class.

Problem 2Class, Sorting, Data Structures, Exception handlingAssume that a lecturer teahces on tow modules CO101 and CO102. Use the set class developed in Problem 1 to determine:a) A list of studends who are taking CO101 but not taking CO102.b) A list of students who are taking both CO101 and CO102.c) A list of students who are taking CO101 or CO102 or both. A student's name can only appear once in a list.

Additionally, a user wishes to display each of the above lists in alphabetical order. You are required to use the Quicksort method to sort any of the above lists.

I have to admit that my head is still spinning after trying to digest this stuff (my experience with templates is mostly around using std::string and std::vector).I really encourage you to write more articles on this.I haven't been this excited about new programming concepts since Turbo Pascal 3.0 came out.

Thank you, fin!Hopefuly, I'll get around to write my next article on how to use/implement 'variant' and 'tuple'. To get some quick ideas, you can take a look at the sample in the latest TTL release. The latest release has 'tuple' as well.I was also thinking about a short article on sizeof()... seems like a simple thing, but in generic programming, sizeof() is one of the most important features. It is amazing what can be done with it.Perhaps, I'll write about sizeof() first... haven't decided yet.

I thought I had a pretty good understanding of C++ until I read Jonathan's (http://www.codeproject.com/csharp/spart.asp) article, which directed me to Spirit http://spirit.sourceforge.net/[^]. When I looked at the Spirit C++ sample code, my first reaction was big time . I'm slowly starting to grasp the concept now, and articles like yours really help -- simple spoon feeding is what I need. That's maybe CodeProjects biggest advantage; it provides a relatively pain-free introduction into pretty hard to grasp stuff.

Your comment on sizeof() made me curios -- can't wait for the next article. And any references on the subject such as on-line tutorials, books, libraries etc. are really appreciated.

Your variant class is cool. Just as a pointer for those who don't know, though, check out www.boost.org. The boost::any class does much the same thing, and has the benefit of being a likely template (pun intended) for something that might end up in the C++ standard someday.

Well, boost::any is quite different from variant.Just to list a few differences:boost::any can hold *any* type, so it doesn't provide the level of type safety that variant does.Obviously boost::any cannot support visitors.

Actually AFAICT, the next release of boost will include boost::variant that has almost the sameinterface as ttl::variant.If you download the boost sources from CVSyou can take a look at it.In fact I used the boost::variant semantic in my variant.You can see the description of ttl::variant vs. boost::variant (to be released)at http://tinytl.sourceforge.net/#variant

Forgot to mention another significant difference.boost::any has to allocate dynamic heap memory with 'new'. ttl::variant never does this.variant does *in-place* construction.So in many cases, variant is much more efficient.

Somehow, "variant" and "typelist" had never attracted me as being in the mainstream of template usage (meaning, not very popular and widely used). However, after reading your excellent article on these two template features, I can only say, "How wrong I've been."

Taken together, they both seem to complement each other and offer enormous power (and flexibility) to the creative thinker. Indeed, "typelist" very much extends the capabilities of template usage where mainstream has left off (meaning, when you find yourself able to deal with a variable number of template parameters, you've got to put your creativity and excitement in check). However, dealing with a "variable number of template parameters" DOES NOT mean quite like how it sounds. It means you are able to deal with a variable number of parameters because now you are able to deal with a variable number of parameter TYPES!! That's the secret!!

If nothing else, I give you a '5' for awakening my interest to this very powerful side of template usage. All of a sudden I have new options in my use of templates.

Thanks for the kudos, WREY!It is really amazind what you can you do with templates.I don't think that the C++ inventors ever thought about how their ideas could be used.They probably thought that templates is just a wayto parameterize a function or data type... but it is so much more.

Thanks for the kudos, WREY!It is really amazind what you can you do with templates.I don't think that the C++ inventors ever thought about how their ideas could be used.They probably thought that templates is just a wayto parameterize a function or data type... but it is so much more.