This is a text-only version of the following page on https://raymii.org: --- Title : C++ variadic template recursive example Author : Remy van Elst Date : 08-06-2019 URL : https://raymii.org/s/snippets/Cpp_variadic_template_recursive_example.html Format : Markdown/HTML --- In this article I'll show you how to use a variadic template in C++. Variadic templates allow you to have a template with a variable number of arguments, also called a parameter pack. Unpacking that pack is more difficult than it should be, so we use a recursive template to iterate over all the parameters one by one. I've also included an example in Python to compare to.

Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics. Please, if you found this content useful, consider a small donation using any of the options below:

I'm developing an open source monitoring app called Leaf Node Monitoring, for windows, linux & android. Go check it out!

Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.

You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $200 credit for 60 days. Spend $25 after your credit expires and I'll get $25!

### Variadic templates Variadic templates allow you to have a template with a variable number of arguments, also called a parameter pack. They were introduced in C++ 11, before that you had to use `va_` macros with the ellipsis `(...)` operator, which is not type-safe and quite complex. My use case was to have a template that allows an arbitrary number of arguments, of a few different types which will all be processed one by one sequentially. If you're looking to get all of the template pack and to something with it at once, this guide isn't for you. That requires either an `initializer list` or a `tuple`. [This][1] is a great article on variadic templates with more examples. [Wikipedia][2] also has a page with some examples. [This][3] is also a good introduction. Quoting Kevin from the last linked article: > When it comes to handling variadic functions, you can't think in the standard `iterative` C++ style. You need to write such functions recursively, with a `base` case, and a `recursive` case that reduces, eventually, into a `base` case. This implies a separate function for each case. It took me a while to find out how to use the argument pack. At the end of this article is a comparison to Python, which is what I was used to before going into C++. There, you can use `Foo(*args)` or `Foo(**kwargs)` and a `for` loop. In C++ that for loop isn't easily possible. Quoting [davmac][5] from lobste.rs who has an explanation on why this is not as easy as I would hope: > C++ for loops were traditionally a run-time loop and so they don't apply to parameter packs which are a compile-time construct only. While a for loop can now be evaluated at compile time (in a constexpr function) their syntax and semantics are unchanged in that case, i.e. they still apply to constructs that are (or at least which can also be) run-time. Allow for loops to iterate through parameter packs would require new syntax and semantics in a language that many feel is already getting too complex. That said I suspect you could do this with something more like a regular loop with C++2x features (or possibly even C++17, I haven't been keeping up to well) e.g. with template lambdas. Unpacking the pack to a `std::tuple` is possible, but tricky to use afterwards. By using the ellipsis `(...)` operator in the correct place (left or right of a parameter name) we can control what happens. Placing the ellipsis to the left of the parameter name declares an parameter pack. You use this in the template declaration, like so: template void Foo(First first, Args... args) { } Placing the ellipsis to the right of the parameter will cause the whole expression that precedes the ellipsis to be repeated for every subsequent argument unpacked from the argument pack. In our example, it is used in the variadic function to call the base function: Foo(args...); The below `Foo()` example is recursive. The template function with `First` and `Args...` calls the template with `Arg`, which performs the actual action we want. Both functions have the same name, thus being overloaded. There also is a function (not template) which takes no arguments, but that is up to you if you need that. The functions could be named different (`Base(Arg)` and `Other(First, Args...)` e.g.). The `First` argument is required to get the 'One or more' behaviour. If you would omit it, `Foo(Args...)` would accept zero or more parameters. ### void Foo() example Tested with `CLion` in C++ 11 mode. // non template function to call with zero arguments void Foo() { std::cout << " "; } // base template with 1 argument (which will be called from the variadic one). template void Foo(Arg arg) { //std::cout << __PRETTY_FUNCTION__ << "\n"; std::cout << arg << " "; } // variadic template with one or more arguments. // ellipsis (...) operator to the left of the parameter name declares a parameter pack, // allowing you to declare zero or more parameters (of different types). template void Foo(First first, Args... args) { //std::cout << __PRETTY_FUNCTION__ << "\n"; Foo(first); Foo(args...); // ellipsis (...) operator to the right of the parameter name will cause // the whole expression that precedes the ellipsis to be repeated for every // subsequent argument unpacked from the argument pack, with the expressions // separated by commas. } int main() { std::string one = "One"; const char* two = "Two"; float three = 3.3333333333; Foo(); // non template std::cout << std::endl; Foo(one); // base template std::cout << std::endl; Foo(one, two); // variadic argument template std::cout << std::endl; Foo(one, two, three); // variadic argument template std::cout << std::endl; Foo(1, 2, three, 4, 5.7, 6/2, "lalala"); // variadic argument template return 0 } Example output: One One Two One Two 3.33333 1 2 3.33333 4 5.7 3 lalala ### PRETTY_FUNCTION __PRETTY_FUNCTION__ contains the name of the current function as a string, and for C++ functions (classes, namespaces, templates and overload) it contains the `pretty` name of the function including the signature of the function. It is a `gcc` [extension][4] that is mostly the same as __FUNCTION__ or __func__ By placing std::cout << __PRETTY_FUNCTION__ << "\n" at the top of the function, you can get an overview of what is called and when. Consider the following example: template void Foo(Arg arg) { std::cout << __PRETTY_FUNCTION__ << "\n"; } template void Foo(First first, Args... args) { std::cout << __PRETTY_FUNCTION__ << "\n"; Foo(first); Foo(args...); } int main() { std::string one = "one"; const char* two = "two"; Foo(one); // base template std::cout << std::endl; Foo(one, two); // variadic argument template std::cout << std::endl; } Will output: void Foo(Arg) [with Arg = std::__cxx11::basic_string] void Foo(First, Args ...) [with First = std::__cxx11::basic_string; Args = {const char*}] void Foo(Arg) [with Arg = std::__cxx11::basic_string] void Foo(Arg) [with Arg = const char*] The first line is the base template. After the newline, the variadic template is called and that calls the base template twice. ### Python In Python preceding a method parameter with an asterisk (`*args`) defines it as a variable non-keyword list of arguments. Preceding with two asterisks (`**kwargs`) defines the parameter as a keyworded list of arguments. The parameters can be named anything as long as the asterisks are there, but convention says to use `*args` and `**kwargs`. A small example of the above `Foo()` method in Python. Newline printing is omited by appending the comma (`,`) to the `print()` function. #!/usr/bin/python def Foo(first, *argv): print(first), print(" "), for arg in argv: print(arg), print(" "), print("") bla = "Hello" Foo('one') Foo('one', 'two') Foo('Remy', 2, 2.4, bla) Output: $ python test.py one one two Remy 2 2.4 Hello An example using keyworded args (`**kwargs`): #!/usr/bin/python def Foo2(**kwargs): if kwargs: for key, value in kwargs.iteritems(): print("%s: %s, ") % (key,value), print("") bla = "Hello" Foo2(first='one') Foo2(first='one', second='two') Foo2(first='one', second='two', three=3, var=bla) Output: first: one, second: two, first: one, var: Hello, second: two, three: 3, first: one, [1]: http://web.archive.org/web/20190608070158/https://eli.thegreenplace.net/2014/variadic-templates-in-c/ [2]: https://en.wikipedia.org/wiki/Variadic_template [3]: http://web.archive.org/web/20190608183836/https://kevinushey.github.io/blog/2016/01/27/introduction-to-c++-variadic-templates/ [4]: https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html [5]: http://web.archive.org/web/20190613053209/https://lobste.rs/s/qswclv/variadic_templates_vs_kwargs_c_makes_it --- License: All the text on this website is free as in freedom unless stated otherwise. This means you can use it in any way you want, you can copy it, change it the way you like and republish it, as long as you release the (modified) content under the same license to give others the same freedoms you've got and place my name and a link to this site with the article as source. This site uses Google Analytics for statistics and Google Adwords for advertisements. You are tracked and Google knows everything about you. Use an adblocker like ublock-origin if you don't want it. All the code on this website is licensed under the GNU GPL v3 license unless already licensed under a license which does not allows this form of licensing or if another license is stated on that page / in that software: This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Just to be clear, the information on this website is for meant for educational purposes and you use it at your own risk. I do not take responsibility if you screw something up. Use common sense, do not 'rm -rf /' as root for example. If you have any questions then do not hesitate to contact me. See https://raymii.org/s/static/About.html for details.