C++

C++ Parameter Packs

This article is about parameter packs in C++.  In this programming world, C++ introduces us to different variadic templates with parameter packs. The parameter packs contain arbitrary types or values. We can efficiently perform our complicated actions through this highly effective technique. The parameter pack is a C++ variadic template that can efficiently handle or manipulate many variable numbers of template arguments. Here, we will demonstrate about parameter packs in detail by exploring their syntax, usage, and the ways to create parameter packs with descriptive examples.

What Are Parameter Packs in C++?

First, packs generally refer to a parameter or argument pack in the C++ programming language. This allows us to use the functions and templates to take different types of parameters to perform relevant operations. In C++, a variadic template is a template that has at least one parameter pack by introducing the parameters that are defined at the time of the function definitions. The parameter pack always permits zero or many template arguments. In programming language, “variadic” means taking or allowing any number of arguments.

Types of Parameter Pack

There are two types of parameter packs in the C++ programming language. These are mentioned as follows:

Let’s describe all these types of parameter packs in detail and with proper examples.

1. Type Parameter Packs

The type parameter packs deal with types and allow handling multiple types within a single parameter.

Syntax:

The syntax of function templates with type parameter packs is given as follows:

Template <typename… Args>
void processArgs (Args… args)
{
// zero or multiple arguments of type parameter packs
}

 
Here, “args” shows the number of arguments.

2. Non-Type Parameter Packs

This parameter pack includes type, values, or references as non-type operations in C++. It manages one or more non-type template parameters at a time, efficiently.

Syntax:

The syntax of the non-type parameter pack is given as follows:

template  <int… Values>
void printValues()
{
   // declare values in parameter packs
}

 
Here, the “values” variable contains all “int” values in non-type parameters.

Creation of Parameter Packs

In this section, we will learn about the parameter’s pack creation and usage in C++. We will create parameter packs differently such as the expanding parameter packs.

Scenario 1: Parameter Packs Expansion

In C++, parameter pack expansion is an expression that holds one or more parameter packs that come after an ellipsis (…).  The usage of ellipsis indicates that parameter packs are expanded.  Along with this, folding expressions in C++ provides us with a better way to operate all the elements of the parameter packs. We can fold the expressions like (…. + args). This implements the whole operation, like “Sum”, in all variables or elements that we pass.

We can also expand the parameter pack within the class template in the same way as the function that we described in the previous paragraph.

Let’s consider the following example:

#include <iostream>
void print() {
    std::cout << std::endl;
}
template <typename T, typename... Args>
void print(T start, Args... args) {
    std::cout << start << " ";
    print(args...);
}
int main() {
    std::cout << "The Elements are: ";
    print(4, 12.5, "test", 'v');
    return 0;
}

 
Here, as you can see, we declared the required libraries. After that, we created a function with zero arguments. The “Void print” function works when the argument is zero and inserts a new line.  After that, we declared another function having multiple arguments. We then passed these templates in the “print” function here. In the end, we called this function our main program. Remember that only the main function code execution displays the result on the console screen.

Output:


The elements that we passed in the function are displayed as seen in the given screenshot.

Scenario 2: Handling of Parameter Packs

Here, we will learn about the different ways through which we can handle the parameter packs in C++. The ways are explained in detail as follows:

1. Forwarding Parameter Packs

In C++, the forwarding parameter packs are introduced as a “std::forward” utility that allows us to forward the parameter packs perfectly to the desired location. Using this, we can preserve their values and references. The following is the syntax:

Syntax:

template<typename Func, typename... Args>
decltype(auto) forwardFunc(Func&& func1, Args&&... args1) {
   return   std::forward<Args>(args1)...);
}

 
Now, let’s explain this type of parameter pack with the help of a proper example:

#include <iostream>
#include <utility>
template <typename T>
void processArg(T&& arg1) {
    std::cout << "The process steps are: " << arg1 << std::endl;
}
template <typename... Args>
void forwardArgs(Args&&... arg1) {
    (processArg(std::forward<Args>(arg1)), ...);
}
int main() {
    forwardArgs(1, "c++ example", 566.6, 'e');
    return 0;
}

 
Here, we declare the libraries. Then, we make a template-like function template that takes a reference argument and forward it by calling the value. We use the “processArg” function name and pass a parameter pack like “T&&” with the passing value of “agr1”. After that, we take a template function again with multiple arguments and call these arguments in the “forwardArgs” function. In the end, we call this function in the main body of the program to show the output on the console window.

Output:


The output of this program is shown in the given screenshot for your help.

    • 2. Conditional Manipulation in Parameter Packs

In this section, when working with parameter packs, all the conditional statements dependent on the packs’ attributes and their components are used. For conditional manipulation, “std::conditional” is used. It works on templates rather than types instead of values.

Syntax:

template<typename... Args>
void processors(Args... args) {
    if constexpr (sizeof...(args) > 0) {
        //  arguments not empty
    } else {
        // arguments are empty
    }
}

 
Here is an example to understand the given syntax better. The complete code of the conditional manipulation in C++ is given as follows:

#include <iostream>
void OddNumArgs() {}
template<typename T, typename... Args>
void OddNumArgs(T first, Args... rest) {
    if (first % 2 ==! 0) {
        std::cout << " Odd Number is:" << first<<"\n" ;
    }
    OddNumArgs(rest...);
}
int main() {
    OddNumArgs(11, 52, 63, 47, 5, 16, 227, 28, 89, 10);
    return 0;
}

 
Here, after declaring the essential libraries for running the desired code, we create a function template for parameter packs. In this function, we check if the passing parameters or values in the function are even or odd numbers. At the end, we pass this function into the main function to show the result that you can see in the following:

Conclusion

At the end of this article, we can say that parameter packs are an effective process for handling the variadic templates efficiently in the programming world. It allows us to work with variable templates with non or multiple arguments for type and non-type templated parameter packs. The folds and expansion of the parameter packs are very interesting. Except that, it also works on an array of function pointers. This is a very versatile concept in the C++ programming language and works in maintaining different complicated scenarios. For better understanding, practice the mentioned examples to see the output and better understand how the code works.

About the author

Kalsoom Bibi

Hello, I am a freelance writer and usually write for Linux and other technology related content