# Type traits

… by popular demand. Here we go! We take a look at how to obtain a type-traits implementation for C++, what they are good for and go through some easy examples to understand what they do.

## Where to get them?

Before we start, you’ll need a type-traits implementation. Boost has a very nice one, which is fully modularized. You can include it by using `#include`

which will put it into the `std::tr1`

namespace that I will use in the examples. Optionally, the TR1 additions to C++ contain it (for example, the Visual C++ Feature Pack has TR1 support).

## What are they?

Well, type-traits allow you to make compile-time decisions based on the properties of a type. Sounds kinda complicated? Well, think about it like this: You have a template class, and the user passes in a type you never heard about. With type-traits, you can get information about the type. The result of a type-trait is passed by its member `value`

which is either `true`

or `false`

. Moreover, there is a `type`

which is a real type (`integral_constant`

, but I’ll omit it here and write a small `bool`

-wrapper-type). We’ll be using this helper structure which turns a boolean into a type:

```
struct True {};
struct False {};
template <bool b> struct BoolToType;
template <> struct BoolToType<true>
{
typedef True type;
};
template <> struct BoolToType<false>
{
typedef False type;
};
```

Obviously, `BoolToType<true>::type`

is `True`

. This comes in handy later.

## How to make use of them

Let’s assume we are implementing a copy routine: `fast_copy (const T* source, T* destination, size_type count)`

. Now, if `T`

has a trivial assign implementation (trivial meaning an assign implementation which is just a `memcpy`

) we *can* just use `memcpy`

, otherwise we have to go into a loop and copy using `T::operator=`

. Now, how can we make the decision at compile-time whether it is a type with a trivial assign or not? You guessed it, with type-traits, specifially `has_trivial_assign`

.

```
#include <type_traits>
#include <cstring>
#include <string>
#include "boolToType.h" // BoolToType helper
// Fast path
template <typename T, typename size_type>
void fast_copy_impl (const T* source, T* destination, const size_type count, const True&)
{
std::memcpy (destination, source, count * sizeof (T));
}
// Slow path
template <typename T, typename size_type> void fast_copy_impl (const T* source, T* destination, const size_type count, const False&)
{
for (size_type i = size_type (); i < count; ++i) {
*destination++ = *source++;
}
}
template <typename T, typename size_type> void fast_copy (const T* source, T* destination, const size_type count)
{
BoolToType<std::tr1::has_trivial_assign<T>::value>::type canUseFastPath;
fast_copy_impl (source, destination, count, canUseFastPath);
}
int main ()
{
std::string arrComplex [10];
int arrSimple [20]; // Will call the loop version fast_copy (arrComplex, arrComplex + 5, 5);
// VC++9 can roll this out to direct copy via registers (!)
fast_copy (arrSimple, arrSimple + 10, 10);
}
```

We turn the boolean result of the type-traits into a type by using the helper (as said above, you could directly overload based on `integral_constant`

), and use it to dispatch between two template functions. Voilà , based on the type, we can choose to use `memcpy`

if possible. And the good thing is, this *will work for any type*. This is something you have no chance to implement on your own as this type-trait relies on (non-portable) compiler support! Another example, how to skip calling `T::~T`

if the destructor does nothing. This can help if you have a large array, and you want to get rid of it quickly - if the destructor is trivial, you can just throw it away, otherwise, you need to clear it. This can be interesting if you have some “scratch-memory” where you allocate blocks from. Here we go:

```
template <typename T, typename size_type>
void array_delete_impl (T* array, const size_type count, const False&)
{
for (size_type i = size_type (); i < count; ++i) {
array[i].~T();
}
}
template <typename T, typename size_type> void array_delete_impl (T* array, const size_type count, const True&) {}
template <typename T, typename size_type> void array_delete (T*
array, const size_type count)
{
array_delete_impl (array, count, BoolToType<std::tr1::has_trivial_destructor<T>::value>::type ());
}
```

## Conclusion

Type-traits are a very powerful tool which can both improve the efficiency of template code and improve the maintainability by not relying on custom traits specialisations. The examples here are just very basic - just take a look at how many type traits are available. In addition, there are special type-traits like `add_reference`

which transform types: They add a qualifier if possible (otherwise, you could wind up having a `const T& &`

which is not allowed in current C++ – will be allowed in C++0x).