Below you can see other examples of meta-functions which manipulate typelists. The first will "return" a type at position POS in the list:
/**
 * Extraction of a type at specific position
 */
template <typename TLIST, int POS> struct tlist_get_type;

template <typename HEAD, typename TAIL, int POS>
struct tlist_get_type< typelist<HEAD, TAIL>, POS > {
   typedef typename tlist_get_type<TAIL, POS-1>::type type;
};

template <typename T, typename TAIL> 
struct tlist_get_type< typelist<T, TAIL>, 0 > {
   typedef T type;
};

template <int POS> 
struct tlist_get_type< nulltype, POS > {
   // no typedef - compilation error
}; 

The first line defines the "interface", as in out first example (and as in all following ones). The main recursive work is defined by the first specialized definition:
template <typename HEAD, typename TAIL, int POS>
struct tlist_get_type< typelist<HEAD, TAIL>, POS > {
   typedef typename tlist_get_type<TAIL, POS-1>::type type;
}; 

It takes the rest of thelist, and tries to find an element at position POS-1. In this example you can also note the 2nd way to "return values" from the meta-functions: returning a type using typedef (until now we used enum to return numeric values). We also had to use typename keyword (we've seen it in the previous sections too).

Next we define a specialized version to terminate the recursion - once POS reached 0, we want to return current type:
template <typename T, typename TAIL> 
struct tlist_get_type< typelist<T, TAIL>, 0 > {
   typedef T type;
}; 

The last version is used for out-of-bound condition: if someone requested an element in 6-th position from the list with 5 elements, compile-time error will be produced:
template <int POS> 
struct tlist_get_type< nulltype, POS > {
   // no typedef - compilation error
}; 


It takes some time to get used to the syntax and to be able to read such constructs easily (if you can ever do this...), this is the reason I preferred to demonstrate those concept in scheme programs first, as their code is much more intuitive.

Following 2 examples look very similar to the first one above, so additional explanations won't help much, you just need to read it by yourself.

/**
 * Find the largest type (in terms of "sizeof")
 */
template <typename TLIST> struct largest_type;

template <typename HEAD, typename TAIL>
struct largest_type< typelist<HEAD, TAIL> > {
   typedef typename largest_type<TAIL>::type _largest_tail;
   typedef typename type_if<sizeof(HEAD) >= sizeof(_largest_tail),
      HEAD, _largest_tail>::type type;
};

template <typename T> 
struct largest_type< typelist<T, nulltype> > {
   typedef T type;
};


/**
 * Find index of a type
 */
template <typename TLIST, typename T> struct index_of_type;

template <typename HEAD, typename TAIL, typename T>
struct index_of_type< typelist<HEAD, TAIL>, T> {
   enum { value = 1 + index_of_type<TAIL, T>::value };
};

template <typename T, typename TAIL> 
struct index_of_type< typelist<T, TAIL>, T > {
   enum { value = 0 };
};

template <typename NOTFOUND> 
struct index_of_type< nulltype, NOTFOUND > {
   // no value defined
}; 


And a code to demonstrate those meta-functions "in action":
void test_typelists(void) {
   typedef TYPELIST_5(char, int, std::string, double, unsigned long) tlist;

   std::cout << "The sizes of 1st and 4th types are: "
                << sizeof(tlist_get_type<tlist, 0>::type) << ", " 
                << sizeof(tlist_get_type<tlist, 3>::type) << std::endl;
   /*THIS LINE SHOULD NOT COMPILE*/ // typedef tlist_get_type<tlist, 5>::type overflow;

   std::cout << "The size of largest type is: "
                << sizeof(largest_type<tlist>::type) << std::endl;

   std::cout << "Index of \"std::string\" is: "
                << index_of_type<tlist, std::string>::value << ", " 
                << "and of \"ulong\" is: " << index_of_type<tlist, unsigned long>::value << std::endl;
 /*THIS LINE SHOULD NOT COMPILE*/ //int notfound = index_of_type<tlist, float>::value;
} 

// The output:
//The sizes of 1st and 4th types are: 1, 8
//The size of largest type is: 32
//Index of "std::string" is: 2, and of "ulong" is: 4

Last edited Nov 30, 2007 at 5:44 AM by migo, version 1

Comments

No comments yet.