Up until now and we were talking about the decorator design pattern we're basically talking about a
decorator over a class so some other class which provides an enhancement to an existing class but you
can do the same for functions.
So let's suppose for example that you have a simple invocation Let's suppose I see out the word hello
to the command line.
Now what I can do is I can for example make a function or a decorator around this chunk of code to provide
logging.
So here is how you would do it.
You make a structure called logger and hear what you can do is you can take this unit of work and stick
it as an entity function that gets kept in the logger's So here I can add a function which is void returning
doesn't take any arguments Alcoa's funk and you can also have the name of whatever it is you're actually
invoking.
So I will generate the constructor to initialize both of these fields.
And then what I can do is I can overload the function call operators so I can redefine the function
call operator.
And here what I can do is I can invoke the function because I have it stored up here.
So here is the function itself but I can also do some logging as well so I can see out the fact that
I'm entering a particular function like so and I can see out the fact that I am exiting a particular
function and in between I would of course have to actually call the function.
So now that we have this Loker what I can do is I can use this laga to wrap the unit of work that I
have here so I would call logger and the first argument would be the lambda which I would use to wrap
whatever it is that I'm doing.
The second is the name of the function.
I'm just going to call it flow function and that's pretty much it.
So now I have a longer and I can call the logger So if I add an extra set of round brackets here I can
actually both initialize the log using its constructor as well as call the logger as well.
So let's take a look at what we get here.
OK so we are entering Hello function.
Then we print the hello and then we exit the hello function.
So far so good.
Now in addition to just keeping the function like we do here you can also have the function as a template
argument.
And this introduces its own set of challenges in C++ because unfortunately you can't infer the template
arguments in a constructor so I'm going to show you how this works so basically we're going to build
something which is almost identical to the logger that we have here.
Let me actually cut and paste this because all we're going to do is we're gonna replace the function
void with a template argument so I'm going to have template func and then I will use this func here
and I will simply use this Phong here func like so.
OK so we now have this template.
And let's not forget the typed name.
Key word here.
We now have this template class called logger 2.
So this is a logger which doesn't use as the function directly but you can still feed it functions and
it's going to execute them just fine except that you cannot do this anymore.
Unfortunately you can do it like this because well it's not going to infer the argument from the invocation
it's actually try compiling it.
I just want you to see that even though Sea-Lion doesn't seem to be complaining about it.
Here we go so longer to use all thok class template requies template argument list which we have to
provide.
So the only way that right now that you can infer the type name here is if you make a helper function.
So if you have a helper function that's going to be OK that's going to be a problem if you have a constructor
call like you have here.
Well this isn't going to work.
So what you would do is you'd make a helper function something like the following sun template type
name phunk auto make logger.
And this is where you provide the function as well as the name.
And you would simply return a longer to function and specifying the function as well as the name.
So this might look as though it is redundant because it certainly feels redundant and feels like you
made a little global factory method but in actual fact this approach is going to let you in for the
type of fonk from the argument.
So what you can do is you can say auto log he calls make a log or two and then you can specify the function
and the arguments so I can just call these copy paste them in here.
And that's my function constructor.
So now I can call the function I can call log.
And this is going to perform the actual logging so it's functionally identical to what we have in the
previous example and this you can see we get exactly the same output.
Now so far I've been cheating because I've been using a function which doesn't really return then you
think doesn't take any arguments because this Seow hello and line.
It's a function with Chaz an empty argument list that doesn't have a return value that we're interested
in.
So we're just calling it discarding the return value and then performing some logging or.
Now what if you have a function which actually takes arguments and does not return certain values.
Well in this case things become a bit more complicated so let's suppose we have a function which adds
two numbers together.
So I have a function called adder which takes double A and B and is going to return a plus b.
But let's also do some diagnostic outlet here so I'm going to say that A plus B is equal to and then
just put a plus be here followed by the end line.
OK so we now have a function which takes two arguments and also needs to return something.
So the decorator that we build for this function is going to be a bit more sophisticated because well
as you may have guessed we need variadic templates in order to be able to construct this thing efficiently.
So essentially what we're looking for is we're looking for a template type name or type name args.
So we're looking for a kind of specialization where you have a structure called laga theory which takes
as a template argument something which has a return value or so a function which has a return value
r and takes a number of arguments and thanks to very other comforts we can do this but one thing we
shouldn't forget is that we need partial specialization so we effectively have to have a declaration
here just template type name struct longer three like so without this bar.
It's not going to work.
So now that we have this out the way we can actually build logger 3.
Now Loga 3 is also going to take a function as well as the name.
And it is going to be a function like before so here is the constructor Actually let's do the members
first of all.
So we're going to have a function that's a nested function returns are and takes a number of arguments.
So that's a function.
And we're also going to have the name of the function as before.
Now let's see if we can generate the good constructor for both of these.
So it looks like we're getting the the constructor that we want here so we're taking the function.
I'm not sure if we want a reference here well let's try it for now let's try keeping it as is.
Now the interesting part is the function call operator.
So we need to return the type r.
And here is operator around brackets and in terms of arguments Well it's the args that we're getting
here.
OK.
So the idea is that we want to get the return value and return that but we also want to do the logging
so let's do the logging.
So the logging is as before that may actually copy it from here.
So the logging is going to be precisely like this.
Now between what we want is going to get the result of the function so we take the function and we call
it with whatever arguments are actually provided and after we're done the logging we return the result.
So this is how you would actually define the class itself.
Now of course we also need a helper just like in the previous example we need a helper function for
actually figuring out the arguments of this particular template class.
And in this case I'm going to do something slightly different.
So let's have a template type name and type name are.
And here what I'm going to do is I'm going to have a function called Make log or three but the first
argument isn't going to be an s to the function.
Instead I'm going to take an ordinary function pointer and I can do that.
I mean I have the return value for the function and I have all of the arguments so if I want a function
pointer all I have to do is I have to say something that returns are.
So it's going to be called func and the arguments are simply Arkes.
That's my function pointer and then the second argument and it is as always the name of the function
we want to create.
So here we return logger 3.
We return logo 3 with the template argument which is all returning and takes a number of args like so.
So returning takes a number of args.
And here in terms of the arguments itself this is where we can construct an the function because remember
the logger actually wants and that's the function we can construct to one from a function pointer.
So here I would simply make a function which returns R and takes the args like so and I constructed
from the arguments that we're actually getting.
So the function in this case and the second argument is name as before.
So we are done and we can now use all of this to get the addition done and also get the logging done
as well so we're going to have our cake and eat it so to speak.
So here is the log log and invocation.
So this is going to be a functional decorator I'm going to call make lager 3.
And here I'm going to pass in a function pointer to add Senatus notice I can do that.
I don't have to build an SD function because I've effectively defined a conversion from one to another
here.
And the second argument is going to be the name of the function.
I would just call it add like so.
And I also can get the results so I can give the result of the location.
Here is where we call the function.
So we call logged out and we can pass in the arguments for this one because the function call operator
this one actually takes a number of arguments so we're going to pass those in.
So I will add two and three together and I will see out result equals and then the actual result.
There we go.
OK so we can now try this find no functional decorator that we go to build Hooray.
Here is the output so we get entering and like so I didn't know where the blank lines came from and
then it's two plus three equals five.
We're sitting and then we're printing the result so you can see this decorator works just fine.
And it gives us both the logging functionality but also it gives us an ability to pass in parameters
using this very clever kind of function call operator definition and it lets us return of the appropriate
value and thanks to making this global function.
We've avoided actually specifying any of the template arguments.
Because if you were to call the constructor of Logo three then unfortunately you'd have to specify those
arguments in order to get anything to work.
But we cheated by making this little utility function which takes care of everything for us.