Type Traits, Part 2

Published July 16, 2005
Advertisement
Type Relations
TR1 also introduces a set of traits that are used to determine how types are related to each other.
Quote:
// [4.6] type relations:template  struct is_same;template  struct is_base_of;template  struct is_convertible;

These are fairly self explanatory. The is_same trait will determine if U is exactly a T. is_base_of will determine if Derived is derived from Base either directly or indirectly. The is_convertable trait allows you to test if you can convert from one type to another type implicitly. The following asserts hold true for these three relational traits:
struct A {};struct B : A {};struct C : B {};struct D { operator int() { return 2; } };assert((is_same<int, int>::value));assert((!is_same<int, const int>::value));assert((!is_same<int, long>::value));assert((is_base_of::value));assert((is_base_of::value));assert((!is_base_of::value));assert((is_convertable<int, long>::value));assert((is_convertable::value));assert((!is_convertable::value));assert((is_convertableint
>::value));








Type Modification
The final set of metafunctionality that I will discuss from TR1 is the ability to modify types.
Quote:
// [4.7.1] const-volatile modifications:template  struct remove_const;template  struct remove_volatile;template  struct remove_cv;template  struct add_const;template  struct add_volatile;template  struct add_cv;// [4.7.2] reference modifications:template  struct remove_reference;template  struct add_reference;// [4.7.3] array modifications:template  struct remove_extent;template  struct remove_all_extents;// [4.7.4] pointer modifications:template  struct remove_pointer;template  struct add_pointer;

These are all fairly self explanatory. Plug in a Type in one end, get a different type (or the same type) out the other end. The two that I will discuss here are remove_extent and remove_all_extents. remove_extent will remove one dimension of an array. If the type is not an array, then it will not modify the type in any way. remove_all_extents works in the same way as remove_extent except that it will remove all dimensions of an array, resulting in the base type. The following asserts hold true for these two metafunctions:
assert((rankint
[][3]>::type>::value == 1));
assert((is_sameint[][3]>::type, int[3]>::value));
assert((is_sameint[][3][4]>::type, int[3][4]>::value));

assert((rankint[][3][3]>::type>::value == 0));
assert((is_sameint[][3][3]>::type, int>::value));







As you can see from the asserts, remove_extent will remove the outermost dimension of the array.

Reader Exercises
Since Coder wanted me to add some exercises to my journal, I will give you two, post your answers as replies to this journal entry, or PM them to me. I will post the answers as a reply to this journal entry.

Exercise 1:
Build a recursive template, like that of remove_all_extents except that it will remove all pointers till it encounters a non-pointer type. For instance:
int ** would become int

Exercise 2:
Build a recursive template that will add a const qualifier to each rank of a pointer type. For instance:
int ** would become int const * const * const.

The following asserts should hold true for these exercises:
assert((is_sameint
const * const * const>::type, const int>::value));
assert((is_sameint ***>::type, int>::value));
assert((is_sameconst int>::type, const int>::value));
assert((is_sameint>::type, int>::value));
assert((is_sameint * const **>::type, int>::value));

assert((is_sameint* const *>::type, int const * const * const>::value));
assert((is_sameint*>::type, int const * const>::value));
assert((is_sameint**>::type, int const * const * const>::value));
assert((is_sameint>::type, const int>::value));



Previous Entry Type Traits, Part 1
Next Entry Type Traits, Part 3
0 likes 8 comments

Comments

johnhattan
WWW = Women Worship Washu
July 16, 2005 07:51 PM
Mushu
class CWashu {
private:
     CWashu() {
          prepareTentacles(); }

public:
     pressLittleRedButton() {
          for (std::set<CGDNETMember>::iterator i = members.begin();i!=members.end();++i) {
               i->ban(); }
     }
};

hur hur hur.
July 16, 2005 10:13 PM
Muhammad Haggag
Alright, I really enjoyed hammering this out. Took me a looooooong time, partly because I implemented is_same, remove_extent, and remove_all_extents for fun, and partly because I need to brush up on my m4d template sk1llz. The most tough part was getting the syntax right [grin]:


//
// remove_all_pointers family
//
template <typename T>
struct remove_all_pointers
{
	typedef T type;
};

template <typename T>
struct remove_all_pointers<T*>
{
	typedef typename remove_all_pointers<T>::type type;
};

template <typename T>
struct remove_all_pointers<T* const>
{
	typedef typename remove_all_pointers<T>::type type;
};

//
// add_consts family and helpers
//
template <typename T, unsigned rank>
struct add_consts_helper
{
	typedef typename add_consts_helper<T, rank - 1>::type* const type;
};

template <typename T>
struct add_consts_helper<T, 0>
{
	typedef const T type;
};

template <typename T>
struct add_consts
{
	typedef const T type;
};

template <typename T>
struct add_consts<T*>
{
	typedef typename add_consts_helper<typename remove_all_pointers<T>::type, rank<T*>::value>::type type;
};

template <typename T>
struct add_consts<T* const>
{
	typedef typename add_consts_helper<typename remove_all_pointers<T>::type, rank<T*>::value>::type type;
};

July 17, 2005 01:32 AM
Washu
Your remove all pointers works fine, however your add_consts fails on the asserts (when i ran it). A hint: you should try and implement it much the same way as the remove_all_pointers, except instead of removing the pointers you just add a const at each level. Below you will find how I did it.

Here is how I implemented them:

template<typename T> struct remove_all_pointers { typedef T type; };
template<typename T> struct remove_all_pointers<T*> { typedef typename remove_all_pointers<T>::type type; };
template<typename T> struct remove_all_pointers<T* const> { typedef typename remove_all_pointers<T>::type type; };

template<typename T> struct add_consts { typedef T const type; };
template<typename T> struct add_consts<T*> { typedef typename add_consts<T>::type * const type; };
template<typename T> struct add_consts<T const*> { typedef typename add_consts<T>::type * const type; };


July 17, 2005 03:19 AM
Muhammad Haggag
My add_consts worked fine on VC++ 2003 (assertions passed), so you've got to be using the 2005 beta?
And in that case, which compiler is correct?

Thanks for your implementation, by the way. Much shorter. So, do I get an F+? [grin]
July 17, 2005 03:37 AM
Washu
I believe the reason yours works for you is how you defined rank. According to TR1, rank works on array types, they do not mention pointer types at all. However you defined your rank to work on pointer types. This is how I have rank defined, as it was described in TR1:

template<class T> struct rank_helper { static const std::size_t value = 0; };
template<class T, unsigned S> struct rank_helper<T[S]> { static const std::size_t value = rank<T>::value + 1; };
template<class T> struct rank_helper<T[]> { static const std::size_t value = rank<T>::value + 1; };
template<class T> struct rank : integral_constant<std::size_t, rank_helper<T>::value> {};

and here is how I believe you wrote your rank (albeight, probably not exactly as it is written here):

template<class T> struct rank_helper { static const std::size_t value = 0; };
template<class T, unsigned S> struct rank_helper<T[S]> { static const std::size_t value = rank<T>::value + 1; };
template<class T> struct rank_helper<T[]> { static const std::size_t value = rank<T>::value + 1; };
template<class T> struct rank_helper<T*> { static const std::size_t value = rank<T>::value + 1; };
template<class T> struct rank_helper<T* const> { static const std::size_t value = rank<T>::value + 1; };
template<class T> struct rank : integral_constant<std::size_t, rank_helper<T>::value> {};

Note the two extra helper templates. Adding in those two helpers causes your templates to pass the assertions.
July 17, 2005 01:28 PM
Muhammad Haggag
Aha! I see now. I did define rank for pointers just for the sake of add_consts, but didn't realize it wasn't in TR1. Thanks again [smile]
July 17, 2005 10:16 PM
Washu
More like an A+, since you actually did the homework [grin]
July 17, 2005 10:59 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement