Transcript for:
Understanding Variadic Function Templates in C++

hey what's going on folks it's Mike here and welcome to the next lesson in our modern C plus plus programming Series in this lesson we're going to continue our discussion on templates and this is a fun one well all the lessons should be fun but this one in particular we're going to be talking about variatic function templates so this is the idea that you can have a function template that can take an arbitrary number of parameters now why might you want to do this well let's go ahead and look at a classic example of a function that takes a variable number of arguments so a very popular function especially if you're coming from the C programming world is printf you can print out as much data as you want in a sort of format string and maybe for folks who have a little bit of C programming experience maybe you have used the standard ARG header here standard arc.h or maybe in C plus plus you've used this as well and you have your variable arguments here if we go ahead down to this example we can go ahead and see how to use this or basically have a function here you sort of set up some structure here to get all the arguments and then you have your start and your end and then you sort of determine what types of arguments you can have now this is a little bit tricky to use and there's actually a lot of moving pieces here and even more so we're doing a lot of this detection to figure out how many arguments we have and go through this control structure at runtime which costs us something so there is a slight disadvantage to this in the sense that we have to do this computation every time we call one of these functions here so instead in C plus plus what we're going to be doing is something with a template which will just again generate a function for us that does the right thing given an arbitrary amount of arguments so with that said let's go ahead and take a look here so where I want to start here is just discussing variatic functions so again we can still use the VAR args from the C library here and use the C header version of that so that is all available and we've got a nice example of how to do this on CPP reference but instead what we want to do is take advantage of this dot dot dot in our template parameters so let me go ahead and explain and build up an example here so what I'm going to go ahead and do is just write a little example here and let's say that our goal is to have some function here so I'll do a c out here where I can just call some function sum here and maybe I just want to add up a bunch of numbers and sometimes I might want six numbers maybe 7 8 or 9 numbers or just any number again a variable amount of arguments so that'll be the goal and let's just go ahead and just start with one number here now how would I write this sum function here well let's just go ahead and write it like a normal function and then we'll go through the exercise of converting it into a template to get some practice there so what I would do here is just create some function here I'd probably guess the return type in this case it looks like an integer and then I'd say that there's some argument here and we'll just return whatever that argument is here okay so let's go ahead and save this here let's give it a compile make sure this works reasonably well and well appears to work here so this is sort of our simplest version of the sum function we have it just takes one argument and sums that up and in a way we're sort of thinking about this in a recursive manner so how would I sum up multiple elements well again I could use a loop or sort of think recursively and just call the sum function over and over again adding up each of the individual arguments here okay so how to do that well first and foremost let's go ahead and improve our sum function and make it a template so it can work with any type maybe you want to work with doubles or Longs or maybe even strings for instance but let's go ahead and just convert this to a template function by typing out template the type that we're going to replace with type name t and then just go ahead through and do our substitutions here for T and again I'll go ahead and give this a run and it will again compile and run and again because of C plus plus um 20 in modern C plus plus we get the automatic template uh parameter arguments um are are deduced here it knows it's an integer but we could be explicit here and this might become important later on but we could just go ahead and pass an INT like this again just as a reminder and run as follows okay but how would we get to the point of doing one two three four here so if I go ahead and run this well we're going to get a bunch of errors here it's going to say well the candidate function that we have is this one and we only see one parameter being passed in here so we want to be able to fix that okay so let's go ahead and look at how to do this uh using our C plus plus syntax here and what we're going to take advantage of is something called a parameter pack so again you can sort of think about this as a bunch of parameters and sort of packing them together well at least syntactically if I just sort of look at this for the syntax I see the type that we have and then a dot dot dot and then whatever the pack name is okay so what are we collecting in this case it's going to be some arguments in our template parameter list that ultimately go into our function okay so let's go ahead and look at what that means in actual C plus plus so I'll keep this here just so we can keep an eye on it and it might be worth actually just looking at some examples here if we scroll down just to see how we use this so we have class or type name here dot dot dot following this to imply that this is a parameter pack and then whatever you want to call it and then our types here or the collection of them we then give a name into our function here okay so this is whatever the types are and then the arguments and we can see a few examples of this as follows okay so let's go ahead and set this up in our C plus plus code here so what I'm going to go ahead and do is add this function here and it's going to look pretty similar to this sum here so let me go ahead and just copy this for now and essentially what I want to do here for our sum function is taken well the first argument here and then just keep calling this sort of base case if you want to think about this recursively which might be useful way to think about it over and over and over again and return the arguments here so it'll look something like this where I have the sum and T and then I want to add in a bunch of arguments so let's go ahead and see what that looks like uh so I would want to add in um another type name here dot dot dot and then the types now of course I'm going to try to give this a name here like args for instance which sort of matches what we're doing just taking in a bunch of arguments and of course they could be of different types but I'm just going to leave it Arc so whatever name might be appropriate you can use and then in our function and I'll try to get the dot dot dots right here we have our args dot dot dot and then however we want to refer to them in the function maybe a lowercase args here okay and then well what are we doing here well we're adding the first argument which I can give this a better name here sometimes start or first would work but let's go ahead and just say start plus our sum and then the arguments here that we're taking in followed by dot dot dot to tell us that we have multiple of them okay that the actual parameter pack a bunch of things that are being collected here okay from our function so let's go ahead and just save this and let's go ahead and give this like a pile and see if this works here and I'll go ahead and make this bigger here and let's go ahead and see if we get any error messages well it seems to compile and if I run it well one plus two plus three plus four go ahead and do the math in your head that should be 10 here so this is actually pretty cool that this actually works here it's almost like magic in a sense and it's pretty cool because well let's go ahead and add something else here like five and I'll go ahead and compile this run it and 15. so awesome so again why might you use this well maybe you want to write your own print function print out a bunch of things or sum a bunch of things up maybe these are integer or floating Point types or maybe things like strings now let's go ahead and just work with this example just a little bit more to see what's going on here though because what I'd like to do here is go ahead and maybe try some unit tests here so let's go ahead and add one two three four five but let's go ahead and just do 2.2 F and 3.0 or maybe 3.7 here just to make sure that we have some doubles and some different types here just to see if this works here and I'll go ahead and compile this still compiles and I run it and hmm well this is kind of interesting here because 1 plus 2.2 plus 3.7 plus four plus five uh that's not 15 last I check we should at least have a 0.9 at the end here so Something Fishy is going on with our types here let's go ahead and see if we can try to get some insights in our favorite tool CPP insights here so let me just copy and paste our code here and let's go ahead and see what's actually being generated because what I found here when I was first learning about this is well a lot of examples would just start off with integers and then I tried some different numbers and ran into this problem so let's go ahead and see if we can fix this and I'll paste this into CPP insights and again this will give us some intuition as to what types were actually generated here so what's kind of neat here and I'll make this just a little bit bigger so you can see what's on the right side again you can see our template here the instantiation here of our sum function and we see that we have one that's returning an integer okay so let's see if we get one that is returning a double well here is our um function template with a variatic amount or variable amounts of arguments here so that sort of matches what we have here and here's our instantiation and it looks like we have one that gives us an INT and then a float and then a double and then an inch an INT and that matches what we have here an INT followed by a float and a double and then two integers okay and then we have another word here that is taking just the last four types here and then we have another one here that's just taking the last three types and then one that's just taking the last two types here okay so uh one thing that's interesting just to see here is how many different instantiations of templates we get so that might be something to consider with this actual feature that amount of code that's actually being generated and that could be a problem depending on different domains that you're working in if code size is really important so use the feature carefully and again here's the actual uh function call here where we can see the different types that have been expanded now interestingly if I want to fix this example since we've seen that well our sum function here just uh the sort of base case if I go up here just returns an integer type here so let's go ahead and play around with our code and see if we can um get one that creates a double type here like what if I just try double here and let's go ahead and run it let's see if we get in instantiation of something with a double well I still have the int and up here's one that looks like it returns a double but I think that's what we had before here double float and hmm okay maybe this will work here let's go ahead and test it out here so I'll just go ahead and change this line here to be just a little bit more specific about how we want to treat our first number here and if I run it then that'll make sure that this one is a double plus the 2.2 which is some sort of floating type here now let's go ahead and just play around with this just a little bit more here like what if I make this a 1 here and then I have a 3.7 here and then I'll go ahead and save this compile it run it and darn back to 14. um but it should have a 0.7 somewhere so the way that I found to fix this is well just to be really explicit about treating our first two types as doubles so that we have a return type that will be a double type so this is something that you can run into and upon my research there's also some other things you can do like um work with common type there are some functions for that that might assist in this but this is just something to be a little bit careful about and especially if you're going to start mixing in types like strings and different things um they have to know how to interact properly with the plus operator so that seemed to be the gotcha or the catch here so just something to be aware of when you're using this function here to check your results and make sure that you're getting something that's at least upon if you're using these integer types using the first two numbers adding them together you get the right type and there are different ways you could sort of cheat here for example if you just change the return type to double if you wanted to be explicit about it but again I felt that was not in the spirit of our templates so I just went ahead and made sure that the first two values were treated as doubles so the subsequent additions were with double values anyways folks I hope you found this useful and at least this part interesting and if you're going to try to use these types of functions do make sure to test them out do make sure to play around with them and they can be again really powerful ways for you to just generate a lot of code and again the advantage of this versus doing things in the old C way with VAR args is we just have the exact function that we need and we don't need to do any additional runtime checks we just have something that will sum things up and you could probably even do more with this with maybe evaluating some of these Expressions at compile time if you've played around with kant's expert but I'll leave that for you to do so folks I hope you found this as a useful lesson and if you did make sure to give it a like And subscribe so you don't miss future lessons and if you have more questions about this type of thing or want to see more of these types of generic programming in c plus plus lessons go ahead and leave a comment below so I know what you're looking for thanks for your time and I hope you had fun