Hello and welcome to C++ Weekly.
I'm your host, Jason Turner.
I'm available for code reviews, contracting,
and on site training.
In this episode, I'm going to explore a feature from C++ 14
that I never appreciated.
And I'm starting to feel a little silly, now
that this has been out for more than five years at this point,
depending on what compiled version you are using,
and never really fully appreciating the power of it.
And I owe this to going to CppCon,
and going to conference talks, and making me think
in new and different ways.
So I do strongly recommend that you go to conferences,
and learn more things.
So in this episode, I'm going to talk about C++ 14's variable
templates.
Now the classic example for a variable template,
if you were to go to the standard library documentation,
is going to look a little bit like this.
So it's a template to give us a particularly typed value.
Now if I want to return or access some various precision
version of pi, I'm going to take advantage
of the new feature of Compiler Explorer
to actually let us execute this code.
Now I can't just say print out pi.
Pi is a template.
I have to give it a template type, OK?
So I'm going to give it float.
And I've just created a floating point representation of pi.
So I get 3.14159.
And here, I'm asking for a double representation of it.
Now I'm, you know, not able to actually see more data here,
because I'm not using setprecision, or anything
like that.
So let's just go ahead and do that real quick.
So as we can see here, this is in the I/O manip header,
and it is standard setprecision.
And I can use it to say, what is my floating point precision?
So let's do that and see where we get.
Going to go ahead and just say 20.
That's more precision than we have.
So I am printing this as a double,
and I am getting 3.141592653589793,
and then this varies here.
I don't get that last 3 2 3.
And if I put this as float, then I
am going to see a lower precision version of it.
Again, get printed out, and things fall down right
around here.
And if I do long double, then I should
get a pretty accurate representation of what
I was just trying to print.
32301, right?
So I've gone off the end of the precision
that I actually provided.
And I believe, let's see.
If I say I want to print an integer version of this,
then I'm going to get a compile error, because I've
used braced initialization.
I can use parenthesized initialization,
or I can use static assert here.
And now I can say, OK.
This is all of the precision anyone
should ever need when printing pi.
It is the value 3.
OK.
So these are what we see when we see examples
of variable templates, which is, in fact,
the topic of this video, not setprecision.
Well, I saw these examples, and I said, I don't get it.
What's the point?
So I wondered, what is the point?
Actually, no.
I didn't wonder that.
I just forgot about it, until I saw someone else
showing me what the point was.
It starts to get a little bit more interesting if we
can do something like this.
So now, I can initialize it by calling a constant expression.
And I can create a content expression variable template.
And that becomes a little bit more interesting.
But I still am kind of at a loss as
to why and where and how I would use this.
And the thing that I learned at CppCon
is that variable templates can be specialized.
So I can do something like--
So recursively defined specialization of context
for variables, just like old school examples
of doing this kind of thing with templates.
Now this is probably not the best use of it.
But now we start to see the power that they can actually
be used for actually relatively complicated things,
and specialization, and partial specialization, the same thing
as class templates.
Opens up a whole other world of possibilities.
Now, the example that I saw at CppCon
that blew my mind was an implementation of the
is same type trait.
I have just created a template, and it is same as false.
OK.
Now I am creating a specialization
of this template, like this.
So if the two types passed in are the same,
then this is going to return true, as
opposed to being false.
So are afloat, then into the same, no.
Then we expect 0 to be printed here.
And in fact, it was.
Is an int and an int the same?
Yes, they are the same.
We're going to expect one to be printed here,
because it's choosing this specialization
of the variable template.
Now apparently, this has a lot of implication
in making much simpler type trait light
things that are actually much more efficient at compile time.
But then to take these variable templates to the next level,
I will give an example that was from Bjorn Fowler on Twitter,
quite a long time ago at this point.
I filed it away as something that I should probably
come back to that.
I didn't quite get the implications of it
back when I saw it.
So we can use variable templates to generate specifically
typed lambdas for us.
And that's interesting.
I can decide that I want to do integral additions with two
floating point numbers.
These are doubles, in this case.
And so I still have my compiler in C++ 14 mode.
I need to be in at least C++ 17 mode,
if I want to use a context for lambda here.
All right.
There we go.
So I just said, I want an add function for integers.
And I used a context spur variable template with a lambda
to do this, which again just falls into the category
of if you understand everything about lambdas,
and how they can be used, and how they are built
by the compiler, you understand everything that matters about
C++.
So thanks for watching this episode of C++ Weekly.
I hope this episode made some sense, and gave you something
that you can apply in your real-world work.