# Overview

When writing C++ code, one may come across the need to have a set of *N* arguments of all identical types for a variadic template type. In other words, it would be nicer to write:

typedef type_extend<1, std::tuple, std::string>::type t1;

typedef type_extend<2, std::tuple, std::string>::type t2;

typedef type_extend<3, std::tuple, std::string>::type t3;

typedef type_extend<4, std::tuple, std::string>::type t4;

instead of:

typedef std::tuple<std::string> t1;

typedef std::tuple<std::string, std::string> t2;

typedef std::tuple<std::string, std::string, std::string> t3;

typedef std::tuple<std::string, std::string, std::string, std::string> t4;

In other words, the goal is to have a positive integer (i.e., the first parameter to **type_extend**) that determines how many times the last argument passed to **type_extend** will be duplicated in an argument list that will be *applied* as the template arguments to the type denoted by the second parameter passed to **type_extend**.

This article explores how to do this using variadic templates which will be part of the upcoming C++ standard.

# Template Template Parameters

In the following code, notice the use of std::tuple appears without any template arguments even though std::tuple *requires* a list of types as its template arguments:

C++ allows the programmer to specify that template arguments are placeholders for *class templates*. Such placeholders are called **template template parameters** and are declared the same as class templates except that `struct`

and `union`

*cannot* be used:

void some_func(T<float>*);

template <template<typename X> typename T> // ERROR

void some_func(T<double>*);

template <template<typename X> struct T> // ERROR

void some_func(T<short>*);

template <template<typename X> union T> // ERROR

void some_func(T<long>*);

Notice that the above code allows the user to specify a `class`

that has **only one** template argument *without specifying the template argument:*

struct Number

{

N num;

};

template <template <typename> class T>

struct SomeClass

{

// This class sets the argument to T as float...

T<float> something;

};

int main()

{

// Notice Number has no arguments...

typedef SomeClass<Number> N;

N n;

n.something.num = 3.14F; // NOTE: num is a float

}

The usefulness of template template parameters is to allow one to omit the template arguments when passing a class template type as a template argument. The downside in using template template parameters are that (a) any use must fully specify all template parameters to the template template placeholder name and (b) the number of template arguments must exactly match the type being passed in. The restriction that (b) places is important to note: the STL containers all have default arguments and therefore they all have at least two arguments –not one!

# Implementing `type_extend`

In order to build up a variable argument list of types, two class templates will be defined: `type_extend`

and `type_extend_impl`

. The `type_extend`

class templates have the three template arguments previously discussed. The `type_extend_impl`

class templates will need to build up the list of template arguments up to the number specified. The purpose of `type_extend`

is to handle the N-th case and the 0-th (i.e., base) case and its definition is straight-forward:

struct type_extend

{

typedef typename type_extend_impl<N-1,T,Arg>::type type;

};

template <template <typename...> class T, typename Arg>

struct type_extend<0,T,Arg>

{

typedef T<> type;

};

In the base case (i.e., in the template specialization `type_extend<0,T,Arg>`

), the computed `type`

is `T`

without any template arguments. In all other cases, the computed `type`

is determined by the definition of `type`

in `type_extend_impl`

.

# Implementing `type_extend_impl`

Since the only way to go from some value of an integer N as a template argument to 0 is to use recursion, the first step is to determine what is the base case's `type`

result that needs to be computed. Since the `type_extend`

class template handled the case where there were no arguments, then the base case of `type_extend_impl`

will need to be `T`

having only one template argument. As for all other cases, the number of arguments needs to be increased by one per recursive iteration. To following code accomplishes this:

unsigned N,

template <typename...> class T,

typename Arg,

typename... Args

>

struct type_extend_impl

{

// This class was invoked with Arg, Args... and to increase the

// Arg one more time we need to add it again which is why Arg

// appears twice below...

typedef

typename type_extend_impl<N-1,T,Arg,Arg,Args...>::type

type

;

};

template <

template <typename...> class T,

typename Arg,

typename... Args

>

struct type_extend_impl<0,T,Arg,Args...>

{

// Base case: Stop the recursion and expose Arg.

typedef T<Arg,Args...> type;

};

Certainly do take time to digest the above, but, the above code works since each recursive call to `type_extend_impl`

except the last adds one `Arg`

to the template argument list and reduces `N`

by one.

# Testing `type_extend`

All that is left is to test that this works. This test will assume the use of one of the GNU C++ version 4.5 or higher compilers. Suitable test code would be:

// Place definition of type_extend_impl here.

// Place definition of type_extend here.

#include <iostream>

#include <typeinfo>

#include <string>

#include <cstdlib>

#include <cxxabi.h> // GCC-specific

template <typename T>

std::string demangled_name_of_type()

{

// NOTE: See G++ Manual Chapter 27.

// http://gcc.gnu.org/onlinedocs/libstdc++/

int status;

char *name = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);

std::string realname(name);

free(name);

return realname;

}

int main()

{

typedef type_extend<0,std::tuple,unsigned>::type test0;

typedef type_extend<1,std::tuple,unsigned>::type test1;

typedef type_extend<2,std::tuple,unsigned>::type test2;

typedef type_extend<3,std::tuple,unsigned>::type test3;

typedef type_extend<4,std::tuple,unsigned>::type test4;

std::cout

<< "0: " << demangled_name_of_type<test0>() << std::endl

<< "1: " << demangled_name_of_type<test1>() << std::endl

<< "2: " << demangled_name_of_type<test2>() << std::endl

<< "3: " << demangled_name_of_type<test3>() << std::endl

<< "4: " << demangled_name_of_type<test4>() << std::endl

;

}

Save it in a file (e.g., called `program.cxx`

and compile it:

When it is run, the following output will appear:

1: std::tuple<unsigned int>

2: std::tuple<unsigned int, unsigned int>

3: std::tuple<unsigned int, unsigned int, unsigned int>

4: std::tuple<unsigned int, unsigned int, unsigned int, unsigned int>

Success!

# Template Aliases

Another feature, not yet implemented by GCC, in the next standard is the ability to alias template types:

using n_tuple = typename type_extend<N,std::tuple,Arg>::type;

Using template aliases would allow one to easily eliminate the need to write `::type`

and to partially substitute template arguments. For example, the **template alias** `n_tuple`

could subsequently be used as follows:

which would be equivalent to the `t3`

typedef at the very top of this file in the **Overview** section.

Update: Template aliases are now supported if you are using GCC v4.7.