Partners: KDAB Whole Tomato Software CppDepend

07 November 2016

Variadic Templates and a Factory Function

Variadic Templates

Variadic Templates from C++11 is probably not a feature that you use on a daily basis. But recently, I’ve come across one refactoring example where I’ve decided to give a try and apply variadics.

Intro

When I was doing some work in some old UI code I’ve noticed several similar lines of code that looked like that:

switch (ControlID)
{
    case ControlA:
    if (Message == MSG_CLICK)
    {
        FirstMenu *pMenu = new FirstMenu("Test");
        pMenu->Show();
        // pMenu is stored in manager and then deleted later... 
        // so no need to delete it here
    }
    break;
    case OtherControl
    {
        // code here...
        break;
    }
    case ControlB:
    if (Message == MSG_CLICK)
    {
        SecondMenu *pMenu = new SecondMenu();
        pMenu->Show();
    }
    break;
}

In the above example code for that shows FirstMenu and SecondMenu is very similar. How can we refactor that into simpler code?

We could go deeper and change the order of this switch statement, but for now, let’s focus only on the menu handling.

I’ve decided that we could wrap the whole test for the click message and a menu invocation into one method. We could use templates or polymorphic types. But then I’ve noticed that one menu has an additional parameter for the constructor. So my simple method wouldn’t work.

So here we need to look at Variadic Templates!

Full code can be found here: http://coliru.stacked-crooked.com/a/d5edfea9c74e7b3c

Improved version

I’ve come up with the following method:

template <typename TMenu, typename... TArg> 
void ShowMenuOnClick(MSG Message, TArg&&... Args)
{
    if (Message == MSG::Click)
    {
        TMenu* pMenu = new TMenu(forward<TArg>(Args)...);
        pMenu->Show();
    }
}

To be honest, I’ve just copied code from make_unique’s implementation :)

How does it work then?

The construction allows passing a variable number of arguments into a template function. This is what I needed for the refactored code: one menu requires one attribute, another menu is constructed without anything:

The code can be now changed into:

switch (ControlID)
{
    case ControlA:
    ShowMenuOnClick<FirstMenu>(Message, "Test");
    break;
    case OtherControl:
    {
        // code here...
        break;
    }
    case ControlB:
    ShowMenuOnClick<SecondMenu>(Message);
    break;
}

Great! We’ve replaced duplicated code with just one line of helper method call.

What’s more, the code should work as before so it’s a good sign :)

Details

First of all, you might wonder why Variadic Templates were needed. Before C++11 if your template code required several parameters you would manually write each declaration/definition on your own. So for example if a template might use up to 4 parameters, you would declare four different options like

template <class T1> 
void Func(T1);

template <class T1, class T2> 
void Func(T1, T2);

template <class T1, class T2, class T3> 
void Func(T1, T2, T3);

template <class T1, class T2, class T3, class T4> 
void Func(T1, T2, T3, T4);

With variadics, you can wrap it into one or two declarations (depending if you want some recursion to happen).

Structure

  • typename... Args is called a template parameter pack.
  • Args... args is called a function parameter pack. Each argument might have different type.

The real benefit of having variadics is that we might have functions that take an arbitrary number of parameters and this will be evaluated at compile time! This could be achieved in the past, but with a lot of effort. Now the code can be much more expressive.

Of course, Variadic templates is not the only method you could use: var args from C are well-known technique used especially in printf style functions. They work quite well (by taking benefit from various stack manipulation tricks), but the logic is executed at runtime, so this costs something. With Variadics we might create a type-safe printf, which takes no time at runtime…

Read more about variadics templates in the section 3.10 of te book Discovering Modern C++.

forward what?

In the variadic function, I’ve also used another thing that should be explained. Although all rules are quite confusing about rvalues/lvalues/xvalues… but for our code, it’s worth to remember the following thing:

Since we’ve used rvalue reference (&&) - to be correct, we might even say it’s a universal reference since there’s type deduction happening - we cannot change the type that is passed to internal function calls. Those references have names in the context of ShowMenuOnClick so they now become regular lvalue references. To pass them with unchanged type we have to wrap them into std::forward.

If you’re curious, there’s a whole section in the book Effective Modern C++ - 5th section, items from 23 till 30 about rvalue references and move semantics.

Summary

Variadic Templates offers a way to specify a function or class that accepts a variable number of arguments. All the work happens at compile time, so there’s no cost at runtime. This feature opens a lot of possibilities like type-safe printf, classes similar to touples or “factory” function that was presented in this post.

  • Do you use Variadic Templates?
  • In what areas they are they are especially useful?

BTW: If you liked this article, please sign up for my free newsletter.

References

Get my free ebook about C++17!

More than 50 pages about the new Language Standard.

C++17 in detail, by Bartlomiej Filipek

© 2017, Bartlomiej Filipek, Blogger platform
Any opinions expressed herein are in no way representative of those of my employers.
This site contains ads or referral links, which provide me with a commission. Thank you for your understanding.