Using Type Traits in C++

A Fundamental Part of Generic Programming


In C++ template metaprogramming, type traits are a fundamental technique by which we can inspect and manipulate properties associated with a type at compile time. Conveniently, the standard library offers dozens of inspective and transformative traits facilities, a few of which we’ll look at here to explore traits at their most fundamental.


What are type traits? At their simplest, type traits are a template struct or class which contain typedef or constant declarations. A simple example from the <type_traits> header is a struct called std::is_integral:


template <class T> struct is_integral;

A simple usage of is_integral would be:

std::cout << std::is_integral<float>::value << std::endl;

std::cout << std::is_integral<double>::value << std::endl;

std::cout << std::is_integral<int>::value << std::endl;

std::cout << std::is_integral<char>::value << std::endl;

The output of which is:

0

0

1

1

This may seem uselessly simple, but these sort of compile-time inspections can be leveraged and combined to achieve more complex generic programming. Suppose we have an algorithm that was written to only operate on integral types. We may not want to limit it to accept only one integral type, but may want to error at compile time if any non-integral type is attempting to use it. For example, consider my_algo, below:


template <typename T>

void my_algo(const T& t)

{

// do something that makes sense only with integral type

}


We can use the std::is_integral trait struct to actually limit the usage of my_algo to integral types only at compile time with the following simple addition:

template <typename T>

void my_algo(const T& t)

{

static_assert(std::is_integral<T>::value, “Int types only!!”);

// do something that makes sense only with integral type

}


Now, we get the following compile-time behavior:

int i;

my_algo(i); // Perfectly fine! It’s an int type

float f;

my_algo(f); // Compile time error!


This is a simple example of the more inspective category of the type traits facilities provided by the standard library. Some other useful members of the <type_traits> header (with self-explanatory usages) include std::is_floating_point, std::is_class, std::is_function, std::is_same, among many others.


We’ve now seen a basic example of the inspective utility of traits classes, but another powerful provision of traits is the ability to transform types. For this simple illustration, we’ll look at std::remove_pointer, which essentially transforms the type T* to the type T. To facilitate this, we’ll be using the more inspective traits type std::is_same, which, as its name indicates, simply checks that two types are indeed the same. The following simple code example illustrates the behavior of is_same and remove_pointer:

std::cout << std::is_same<int, int>() << std::endl;

std::cout << std::is_same<int, int*>() << std::endl;

As you’d probably imagine, this yields the output:

1

0

If we augment the above code slightly, in the following way:

std::cout << std::is_same<int, int>() << std::endl;

std::cout << std::is_same<int, std::remove_pointer<int*>::type >()

<< std::endl;

We now get the following output:

1

1

As its name would indicate, std::remove_pointer simply converted the initial pointer type to the type pointed to. Other simple, yet very useful transformative traits provided by <type_traits> include std::remove_const, std::add_pointer, std::make_signed, and std::make_unsigned, among others.

We’ve now seen two very simple examples of both the inspective and altering uses of type traits classes. These illustrations, on their own may seem of little or limited utility. When used in composition, however, some very elegant and complex compile-time behavior can be achieved.


Further investigation of traits classes and their applications reveal some very impressive uses of these simple classes to enforce policies, create concepts, and more. While they may seem dated (and pre-date some subsequent evolution of the C++ language), highly recommended browsing would be both Herb Sutter’s “Exceptional C++” and “Modern C++ Design” by Andrei Alexandrescu for extraordinarily impressive examples of type traits usage in C++ design.


Written by Brian Sohr

Principal Software Developer

d1e1871a85e906df5b85bace3dbfd254.jpg

INNOVATION FACILITY NOW OPEN

PSI's state-of-the-art Innovation Facility is now open in Valparaiso, FL. It is designed to provide a cyber secure ecosystem for development of new technologies and approaches, illustrating the company’s commitment to deliver excellence to its customers. Watch a video about the Innovation Facility.