C++ Insights - Variadic Templates

Contents[Show]

Variadic templates are a C++ feature which looks quite magic the first time you see it. Thanks to C++ Insights, most of the magic disappears. 

 

04 variadic templates

Variadic templates are one of the powerful new constructs we have since C++11.

Variadic Templates

They are great because we can have a function that takes multiple arguments and still is strongly typed. We do not need a format specifier to cast some memory from the stack into a type. Variadic templates or in this case more precisely variadic function templates, expand into functions as we would write them. The so-called parameter pack gets expanded. During this process, each parameter is simply separated by a comma, just like we would write the function. Here is a basic example:

template<typename T>
T add(const T& arg)
{
  return arg;
}

template<typename T, typename... ARGS>
T add(const T& arg, const ARGS&... args)
{
  return arg + add(args...);
}

int main()
{
  return add(1, 2u, 3u);
}

The single argument overload is required to terminate the recursion I used here. Let’s use C++ Insights to see what’s going on under the hood:

template<typename T>
T add(const T& arg)
{
  return arg;
}

/* First instantiated from: insights.cpp:10 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
unsigned int add<unsigned int>(const unsigned int & arg)
{
  return arg;
}
#endif


template<typename T, typename... ARGS>
T add(const T& arg, const ARGS&... args)
{
  return arg + add(args...);
}

/* First instantiated from: insights.cpp:15 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
int add<int, unsigned int, unsigned int>(const int & arg, const unsigned int & __args1, const unsigned int & __args2)
{
  return static_cast<int>(static_cast<unsigned int>(arg) + add(__args1, __args2));
}
#endif


/* First instantiated from: insights.cpp:10 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
unsigned int add<unsigned int, unsigned int>(const unsigned int & arg, const unsigned int & __args1)
{
  return arg + add(__args1);
}
#endif


int main()
{
  return add(1, 2u, 3u);
}

Pay attention to the types. I used 2u and 3u which results in two unsigned int arguments and one signed int. Due to the arrangement of the parameters the return type of add is int which leads, as C++ Insights shows use, to an implicit cast in add. One additional insight C++ Insights shows us.

Fold Expressions

With C++17 and fold-expressions we can reduce our code to this:

template<typename... ARGS>
auto add(const ARGS&... args)
{
  return (args + ...);
}

int main()
{
  return add(1, 2u, 3u);
}

I really like how the new standards make us write less and less code. The result of C++ Insights changes as well:

template<typename... ARGS>
auto add(const ARGS&... args)
{
  return (args + ...);
}

/* First instantiated from: insights.cpp:9 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
unsigned int add<int, unsigned int, unsigned int>(const int & __args0, const unsigned int & __args1, const unsigned int & __args2)
{
  return static_cast<unsigned int>(__args0) + __args1 + __args2;
}
#endif


int main()
{
  return static_cast<int>(add(1, 2u, 3u));
}

Of course, you can write variadic class templates as well. Have a look at this code sample:

template<int...>
struct add;

template<>
struct add<>
{
  static constexpr int value = 0;
};

template<int i, int... tail>
struct add<i, tail...>
{
  static constexpr int value = i + add<tail...>::value;
};

static_assert(6 == add<1, 2, 3>::value, "Expect 6");

We have a variadic class template which calculates the sum of an arbitrary amount of numbers. C++ Insights shows all the instantiations that happen in the background to calculate the result. Here we can see how it pops one number each time until there are no more left:

template<int...>
struct add;

/* First instantiated from: insights.cpp:16 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct add<1, 2, 3>
{
  inline static constexpr const int value = 1 + add<2, 3>::value;
  
};
#endif


/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct add<2, 3>
{
  inline static constexpr const int value = 2 + add<3>::value;
  
};
#endif


/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct add<3>
{
  inline static constexpr const int value = 3 + add<>::value;
  
};
#endif


template<>
struct add<>
{
  static constexpr int value = 0;
};

template<int i, int... tail>
struct add<i, tail...>
{
  static constexpr int value = i + add<tail...>::value;
};

/* PASSED: static_assert(6 == add<1, 2, 3>::value, "Expect 6"); */

Reference to an Array

One more thing about templates is that they can take a reference to an array which prevents an array from decaying to a pointer:

template<typename T, int N>
void Rx(T (&data)[N])
{
  // assuming char here
  static_assert(sizeof(data) == 5);
}

int main()
{
    char buffer[5]{};

    Rx(buffer);
}

In C++ Insights you can see that the instantiation contains the type as well as the size of the array:

template<typename T, int N>
void Rx(T (&data)[N])
{
  // assuming char here
  static_assert(sizeof(data) == 5);
}

/* First instantiated from: insights.cpp:12 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void Rx<char, 5>(char (&data)[5])
{
  /* PASSED: static_assert(sizeof(data) == 5); */
}
#endif


int main()
{
  char buffer[5] = {'\0', '\0', '\0', '\0', '\0'};
  Rx(buffer);
}

Another thing, aside from templates, you can see in this example the effect of braced initialization of buffer. The compiler fills all elements of the array for us with the default value. This means that we can say goodbye to the good old memset and make our programs faster and safer.

I hope I could show you how C++ Insights can be helpful if it comes to templates. For me, it is a vital instrument when teaching and explaining templates especially variadic templates. Try it out and tell me about your experience.

I’d like to thank Rainer for the opportunity to share information about C++ Insights on his popular blog!

Have fun with C++ Insights. You can support the project by becoming a Patreon or of course with code contributions.

Stay tuned for more insights about C++ Insight ... . The next post is about lambdas.

Andreas

 

 

 

Thanks a lot to my Patreon Supporters: Paul Baxter,  Meeting C++, Matt Braun, Avi Lachmish, Roman Postanciuc, Venkata Ramesh Gudpati, Tobias Zindl, Dilettant, Marko, Ramesh Jangama, G Prvulovic, Reiner Eiteljörge, Benjamin Huth, Reinhold Dröge, Timo, and Abernitzke.

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
Tags: templates

Add comment


Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code

Visitors

Today 137

All 2678078

Currently are 118 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments