C++ Core Guidelines: Programming at Compile Time with the Type-Traits


My journey through programming at compile time began in the last posts with template metaprogramming. Today, I jump from C++98 to C++11. This is a jump to the type-traits library which is template metaprogramming in a standardised way.


The type-traits library is part of C++ since C++11. Its origin is in boost. The type traits supports type checks, type comparisons, and type modifications at compile time. The library has now more than 100 functions but each C++ standard adds new ones.

I will not go into the details of the type-traits library because I have already written posts to it: type-traits library. On the contrary, to continue my introduction to programming at compile time, I can not skip the type-traits library. In the end, here is my short introduction to the type-traits library. For more information, I add links to my older posts.

First of all, what's inside the type-traits library?

The Type-Traits Library

The library consists of type checks, type comparisons, and type modifications. Let me start with the type checks.

Type Checks

Each type belongs precisely to one primary type category.

Primary type categories

Here are they:

template <class T> struct is_void;
template <class T> struct is_integral;
template <class T> struct is_floating_point;
template <class T> struct is_array;
template <class T> struct is_pointer;
template <class T> struct is_null_pointer;
template <class T> struct is_member_object_pointer;
template <class T> struct is_member_function_pointer;
template <class T> struct is_enum;
template <class T> struct is_union;
template <class T> struct is_class;
template <class T> struct is_function;
template <class T> struct is_lvalue_reference;
template <class T> struct is_rvalue_reference;

The following program gives you to each primary type category a type.


//  primaryTypeCategories.cpp

#include <iostream>
#include <type_traits>

struct A{
  int a;
  int f(int){return 2011;}

enum E{
  e= 1,

union U{
  int u;

int main(){
  std::cout <<  std::boolalpha <<  std::endl;

  std::cout << std::is_void<void>::value << std::endl;
  std::cout << std::is_integral<short>::value << std::endl;
  std::cout << std::is_floating_point<double>::value << std::endl;
  std::cout << std::is_array<int []>::value << std::endl;
  std::cout << std::is_pointer<int*>::value << std::endl;
  std::cout << std::is_null_pointer<std::nullptr_t>::value << std::endl;
  std::cout << std::is_member_object_pointer<int A::*>::value <<  std::endl;
  std::cout << std::is_member_function_pointer<int (A::*)(int)>::value << std::endl;
  std::cout << std::is_enum<E>::value << std::endl;
  std::cout << std::is_union<U>::value << std::endl;
  std::cout << std::is_class<std::string>::value << std::endl;
  std::cout << std::is_function<int * (double)>::value << std::endl;	
  std::cout << std::is_lvalue_reference<int&>::value << std::endl;
  std::cout << std::is_rvalue_reference<int&&>::value << std::endl;
  std::cout <<  std::endl;



Here is the output of the program:


If you want to know how this magic works, my post Check Types provides more information.

Based on the primary type categories are the composite type categories.

Composite Type Categories

The following table gives you the relation between the primary type categories and the composite type categories. 


There are more type checks possible with the type-traits.

    template <class T> struct is_const;
template <class T> struct is_volatile;
template <class T> struct is_trivial;
template <class T> struct is_trivially_copyable;
template <class T> struct is_standard_layout;
template <class T> struct is_pod;
template <class T> struct is_literal_type;
template <class T> struct is_empty;
template <class T> struct is_polymorphic;
template <class T> struct is_abstract;
template <class T> struct is_signed;
template <class T> struct is_unsigned;
template <class T, class... Args> struct is_constructible;
template <class T> struct is_default_constructible;
template <class T> struct is_copy_constructible;
template <class T> struct is_move_constructible;
template <class T, class U> struct is_assignable;
template <class T> struct is_copy_assignable;
template <class T> struct is_move_assignable;
template <class T> struct is_destructible;
template <class T, class... Args> struct is_trivially_constructible;
template <class T> struct is_trivially_default_constructible;
template <class T> struct is_trivially_copy_constructible;
template <class T> struct is_trivially_move_constructible;
template <class T, class U> struct is_trivially_assignable;
template <class T> struct is_trivially_copy_assignable;
template <class T> struct is_trivially_move_assignable;
template <class T> struct is_trivially_destructible;
template <class T, class... Args> struct is_nothrow_constructible;
template <class T> struct is_nothrow_default_constructible;
template <class T> struct is_nothrow_copy_constructible;
template <class T> struct is_nothrow_move_constructible;
template <class T, class U> struct is_nothrow_assignable;
template <class T> struct is_nothrow_copy_assignable;
template <class T> struct is_nothrow_move_assignable;
template <class T> struct is_nothrow_destructible;
template <class T> struct has_virtual_destructor;


Many of the function templates like is_trivially_copyable have the name component trivially. That means that these methods are not implemented by you but by the compiler.  Requesting a method from the compiler with the keyword default is also trivial.

Type Comparisons

The type-traits library support three kinds of comparisons:

  • is_base_of<Base, Derived>
  • is_convertible<From, To>
  • is_same<T, U>

The following example uses all three functions


// compare.cpp

#include <cstdint>
#include <iostream>
#include <type_traits>

class Base{};
class Derived: public Base{};

int main(){
  std::cout << std::boolalpha << std::endl;
  std::cout << "std::is_base_of<Base, Derived>::value: " 
            << std::is_base_of<Base, Derived>::value << std::endl;
  std::cout << "std::is_base_of<Derived, Base>::value: " 
            << std::is_base_of<Derived, Base>::value << std::endl;
  std::cout << "std::is_base_of<Derived, Derived>::value: " 
            << std::is_base_of<Derived, Derived>::value << std::endl;
  std::cout << std::endl;
  std::cout << "std::is_convertible<Base*, Derived*>::value: " 
            << std::is_convertible<Base*, Derived*>::value << std::endl;
  std::cout << "std::is_convertible<Derived*, Base*>::value: " 
            << std::is_convertible<Derived*, Base*>::value << std::endl;
  std::cout << "std::is_convertible<Derived*, Derived*>::value: " 
            << std::is_convertible<Derived*, Derived*>::value << std::endl;
  std::cout << std::endl;
  std::cout << "std::is_same<int, int32_t>::value: " 
            << std::is_same<int, int32_t>::value << std::endl;
  std::cout << "std::is_same<int, int64_t>::value: " 
            << std::is_same<int, int64_t>::value << std::endl;
  std::cout << "std::is_same<long int, int64_t>::value: " 
            << std::is_same<long int, int64_t>::value << std::endl;
  std::cout << std::endl;

and has the expected outcome.


Programming At Compile Time

Okay let's step back and think about the functions of the type-traits library. Here are a few observations.

  • The functions from the type-traits library are metafunctions because they run at compile time. Metafunctions are class templates
  • The arguments of the metafunctions which goes into the sharp brackets (<...>) are metadata. Metadata are (in this case) types.
  • The return value of the functions is the (::value). This is just an alias. Since C++17 there is a simpler form for getting the result: instead of std::is_void<void>::value, you just type std::is_void_v<void>.

I hope these three observations remind you of my last post. These are exactly the conventions, I presented in my previous post to template metaprogramming: C++ Core Guidelines: Programming at Compile Time.

What's next?

If a function from the type-traits library wants to return a type and not a value, you have to ask for it with ::type. My next post shows, which type modifications does the type-traits library supports at compile time. In the end, the type-traits library has two goals: correctness and optimisation.




Thanks a lot to my Patreon Supporters: Eric Pederson, Paul Baxter,  Meeting C++, Matt Braun, Avi Lachmish, Roman Postanciuc, Venkata Ramesh Gudpati, Tobias Zindl, Dilettant, Marko, Ramesh Jangama, and Emyr Williams.


Thanks in particular to:  TakeUpCode 450 60


Get your e-book at Leanpub:

The C++ Standard Library


Concurrency With Modern C++


Get Both as one Bundle

cover   ConcurrencyCoverFrame   bundle
With C++11, C++14, and C++17 we got a lot of new C++ libraries. In addition, the existing ones are greatly improved. The key idea of my book is to give you the necessary information to the current C++ libraries in about 200 pages.  

C++11 is the first C++ standard that deals with concurrency. The story goes on with C++17 and will continue with C++20.

I'll give you a detailed insight in the current and the upcoming concurrency in C++. This insight includes the theory and a lot of practice with more the 100 source files.


Get my books "The C++ Standard Library" (including C++17) and "Concurrency with Modern C++" in a bundle.

In sum, you get more than 600 pages full of modern C++ and more than 100 source files presenting concurrency in practice.


Get your interactive course


Modern C++ Concurrency in Practice

C++ Standard Library including C++14 & C++17

educative CLibrary

Based on my book "Concurrency with Modern C++" educative.io created an interactive course.

What's Inside?

  • 140 lessons
  • 110 code playgrounds => Runs in the browser
  • 78 code snippets
  • 55 illustrations

Based on my book "The C++ Standard Library" educative.io created an interactive course.

What's Inside?

  • 149 lessons
  • 111 code playgrounds => Runs in the browser
  • 164 code snippets
  • 25 illustrations

My Newest E-Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code


Today 2213

Yesterday 7957

Week 34735

Month 189330

All 4810224

Currently are 247 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments