• entries
    146
  • comments
    436
  • views
    197368

Type Traits, Part 2

Sign in to follow this  
Washu

259 views

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));



Sign in to follow this  


8 Comments


Recommended Comments

class CWashu {

private:
CWashu() {
prepareTentacles(); }

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

hur hur hur.

Share this comment


Link to comment
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;
};

Share this comment


Link to comment
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; };


Share this comment


Link to comment
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]

Share this comment


Link to comment
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.

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now