C++ Insights - Variadic Templates

Contents[Show]

Variadic templates are a C++ feature that looks quite magic the first time you see them. 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  add is int which leads, as C++ Insights shows the use, to an implicit cast in add. One additional insight C++ Insights shows us.

 

Rainer D 6 P2 540x540Modernes C++ Mentoring

Be part of my mentoring programs:

 

 

 

 

Do you want to stay informed about my mentoring programs: Subscribe via E-Mail.

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 that 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: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, and Rob North.

 

Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

My special thanks to PVS-Studio PVC Logo

 

My special thanks to Tipi.build tipi.build logo

 

My special thanks to Take Up Code TakeUpCode 450 60

 

Seminars

I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)

German

Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

  • C++ - The Core Language
  • C++ - The Standard Library
  • C++ - Compact
  • C++11 and C++14
  • Concurrency with Modern C++
  • Design Pattern and Architectural Pattern with C++
  • Embedded Programming with Modern C++
  • Generic Programming (Templates) with C++

New

  • Clean Code with Modern C++
  • C++20

Contact Me

Modernes C++,

RainerGrimmDunkelBlauSmall

 

Stay Informed about my Mentoring

 

Mentoring

English 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

Course: The All-in-One Guide to C++20

Course: Master Software Design Patterns and Architecture in C++

Subscribe to the newsletter (+ pdf bundle)

All tags

Blog archive

Source Code

Visitors

Today 1896

Yesterday 4344

Week 38774

Month 19020

All 12097229

Currently are 156 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments