Transformations between User Input/Output and Type Lists

Type lists are an important way to represent ordered and unordered sets of types at compile time. These types can be real structure- or class types bundling runtime algorithms etc., but they can also convey actual data at compile time. In order to apply certain compile time processing to data, this data needs to be transformed from and to other representations, which can be provided by the programmer and consumed by run time programs. This article shows how to transform back and forth between strings and character type lists.

Wrapping characters into Type Lists

At first, a type is needed which can carry one actual character, without having to instantiate it. This is the requirement for all value-carrying types in order to be able to use them at compile time. Using that type, it is possible to compose character type lists, which carry whole strings.

char_t‘s only template parameter is an actual character. To carry the character ’a’, one just instanciates it like this: char_t<'a'>. The character can now be accessed via the value member of the structure type, both at compile- and at run time:

This type is now fundamental to character type lists.

Converting from Strings to Type Lists

Using type lists, these can now easily be chained together, using the make_t helper from the previous article. (Link to the article which explains how to create type lists)

Although make_t’s purpose is to make type list creation less clumsy, this does not look optimal.

Character type lists can now be instantiated like this:

This is already a significant improvement over what we had before. Pretty nice, but the real optimum would be a transformation from an actual C-string in the form "abc" to a type list.

Of course, that is also possible:

Before continuing with the following lines of code: What is a string provider?

A string, or a string pointer, cannot just be used as template parameters directly. Therefore a type carrying a string as payload and provides static access to it is needed:

This type can now be used as a template parameter by template classes, and the template code can access its static string member. Because of this additional, but necessary, indirection it is called a string provider.

This is as easy as it gets. Having to define a string provider around every simple string is still a lot of scaffolding, but this is still the only reasonable way to convert long C-strings into type lists.

Converting from Type Lists to C-Strings

Imagine a type list with character payload as the result after the execution of some meta programming algorithm.

In some cases the wanted output form is a C-string. This is the exact reverse operation from what we just implemented before.

The generic idea is to convert a type list to a variadic character template parameter list. That variadic list can be used to initialize a character array, which can then be provided to the user:

This code example is different than the others before, because it relies on inheritance. It would have been possible to implement the others with inheritance, too, or implement this one defining local type type variables etc., but i found this form to be the shortest and most useful one, while still being nicely readable.

By instanciating tl_to_vl<some_type_list>, a chain of inheriting classes is unrolled, and the last base class, which is the recursion abort type from line 10, defines the static str() function. Because every member of a struct is public by default, the actually instantiated outer type tl_to_vl<some_type_list> also provides this function, which is directly callable.

Example of how to print a type list on the terminal, after converting it into a C-String:

When compiling code like this, the assembly code will still result in a function call of str(), which returns a pointer to the C-string, and then a call of puts.

Compiling the code without any optimization (clang++ [clang-703.0.29]):

Compiling the code with -O1 or -O2 optimization (clang++):

The disassembly shows that the string is just read out of the binary, where it is available without any processing. It is pretty nice to see that there is no trace of any meta programming code in the binary. Apart from those strange and long symbol names, everything looks as if the string was hard coded into the binary by hand to its resulting form.

The next article will deal with template meta programs which transform character type lists in order to do useful things with them.