- This afternoon we're going to talk
about function templates
and how they really work.
As has become my custom in recent years,
I would like to begin by asking your help
in thanking someone very important to me
and that would be my wife
who fabricates all the ties
that I wear at these conferences.
So if you'd kindly help me thank her,
I would appreciate it.
(clapping)
Thank you all, I'll make sure she sees
this part of the video.
(laughing)
So in this talk, we're going to discuss
how compilers process function templates.
In particular the synthesis
of function declarations,
the instantiation of function definitions,
both from a function template.
We'll run across template
argument deduction
and a few other algorithms
that compilers use
like name lookup, overload resolution,
partial ordering, et cetera.
So these are the things
we're gonna talk about.
We will also discuss function
template specialization
and in particular, we'll
talk about why this
is probably not a good
idea for programmers to do.
When it comes to explicit ones,
we'll make some recommendations
about what you can do instead.
And toward the end, as time permits,
we'll talk a little bit about
the future of function templates.
We'll look at a proposal that's
under discussion for C++ 20
and the core language and another one
in the standard library.
So with that, I don't usually
do this but it turns out
that when I started to prepare this talk,
I looked around for what
had already been discussed
and I discovered an incredible
amount of misinformation,
which I like to call myth-information.
I'm going to quote, and
I'm not gonna tell you
where the quote comes from
because I want not to embarrass anybody.
But somebody wrote, "Function templates
"are special functions."
And that's just not true.
Function templates are not functions
of any kind, let alone special.
As you're probably aware
the term special functions
in C++ refers to those member functions
that a compiler can
sometimes generate for us.
And in mathematics by the way,
the term special functions,
it has a much older origin,
it goes back about 200 years
in case you didn't know that.
At the high school level it refers
to functions like the trig functions,
exponentials, things like that.
At the university level,
we have Bessel functions,
Neumann functions, Laguerre, Lagendre,
and you may or not be
aware but since C++ 17,
we have a whole bunch of
these university level
special functions now
available through C Math.
Second quote, somebody claims
that a function template
behaves like a function.
No.
There is absolutely no behavior
that a function template has
that is in any sense function-like.
Examples, you can't call it.
You can't take its address.
It doesn't even exist once the programs
in compiled and is running.
And final quote, somebody
wants to give an example
and introduces it by saying,
"Here is the templated function."
Well, no.
There is no such thing
as a templated function.
We have function templates.
We don't have template functions,
we don't have templated functions.
The order of the words
does make a difference.
Here's my favorite example of that.
Think about the difference
between chocolate milk
and milk chocolate, right?
One's a beverage, the other
one's a candy for children.
They're very different.
The order of our words
does make a difference.
So a quick introduction,
what really is a function template?
Let me show you two examples of code.
The first is very simple,
just an ordinary function.
You give me two int values
and this function calculates
and returns the value of
the min of the two, 'kay?
You may quibble about how
the algorithm is phrased.
I claim this is the only
right way to code it
but we can talk about
that some other time.
But notice that the logic
would apply equally well
to other types, right?
To values that are float
or double or long double
or long or long long or unsigns.
Even to std strings and maybe
your type and my type as well.
I don't want to write
all of those functions.
What I'd rather do is write a function
in terms of some placeholder type.
Let's name a T for the moment.
Notice the only thing I've changed
is I've substituted T in place of int.
And of course C++ has this rule you have
to declare before you can use.
So there's my declaration for T.
As you're probably aware, instead
of writing class up there,
you can write type name and it has exactly
the same meaning.
It's a placeholder for a type.
That's the template parameter.
When we talk about templates,
we have to be a little bit careful,
especially with function templates
because you have not only the traditional
function parameters and
function arguments in the call
but we now also have template parameters
and template arguments.
So we need to be a little bit careful
to distinguish which one we mean.
Usually it's clear from
context but sometimes
I will stress one or the other.
So the point is that a compiler will treat
a function template just like
a builder treats a blueprint.
Builders use blueprints to make homes
and other kinds of buildings.
Compilers use blueprints
to make function
declarations and definitions.
Each one of those applies
whatever you have written
in the templates definition to values
or types of a specific type.
And then that specific type replaces
wherever you have used the placeholder.
Okay.
It's important to understand
that compilers don't do this willy nilly.
They do this when and as necessary
and typically, it's because that there is
a call in the client code
and the compiler says,
hm, I need a function to be called.
Lemme go find one.
If I can't find one, I
may have to make one.
And that's what this is all about.
One final piece of information.
If you are new to templates,
templates are typically
provided in headers.
And there's a very simple reason for that.
Imagine a builder who's told,
well, there's a blueprint somewhere
but we're gonna not let you look at it.
So we have to be sure that
we provide our templates
in some place where the entirety
of the template is clearly
visible to the compiler
at the point that it needs to be used.
There's also some fairly
standard terminology,
let's make sure we've got.
Function templates in particular
are often characterized
as generic algorithms and by generic,
we typically mean that they are agnostic
as far as type is concerned.
This algorithm works no matter what type
you might provide me here.
Provided of course that type
meets some specific requirements.
In my example on the previous page,
the min algorithm needed
a type that was copyable
and had a less than and so forth.
Alright.
But any type that meet
those few requirements,
that concept if you will, would work.
So, from a function template, a compiler
can do one of two things as needed.
It can synthesize, and
that's the word we use.
Synthesize a declaration and technically,
that's not quite right.
What it really does is
synthesize a signature
but that's very close to a declaration
and so will tend to use
the term declaration
because most of us are used
to declaration versus definition.
And the other thing
that a compiler will do
with the template is to instantiate it.
Again, both of these actions are taken
only when and as needed.
Once instantiated, you have
a function at that point
and we refer to that
function as a specialization.
And again, in the specialization,
some specific template
argument has replaced
the template parameter.
Consistently, wherever it arises,
in that template's definition.
The point of course,
being that specializations
are type-specific; they care
very much about the type.
They're no longer type-agnostic.
Now as you're probably aware,
C++ also allows explicit specializations,
as I mentioned in the introduction.
Usually, it's the compiler that does the,
that instantiates the specializations
but the language does
permit us programmers
to provide our own specializations
as a form of customization.
Here's the general purpose algorithm
but for this specific type,
I would like it handled
in a slightly different way.
So explicit specializations
are thought of typically
as a form of customization
of the generic template.
For most cases, use the
general, the generic template.
In this particular case, do it this way.
Now, we're going to recommend
that you not do that.
Okay?
But we're not ready to say why not.
So gimme a few minutes, we'll get there.
So let's start with an example.
All I've done here is overload the name g.
Please look at these in detail.
We'll look at this for another
page or so, after this one.
I am number three of course
is the easiest of all.
That's just an ordinary function.
Plan old function, takes a
double, doesn't return anything.
Number one of course,
is a function template.
Number two is an explicit specialization
and if you've not seen this before,
the easy way to tell that this
is an explicit specialization
is just to look at what
I've just highlighted.
The empty angle brackets.
That means this is an explicit
function template specialization.
Okay?
And it'll always look like
that for function templates.
Now I have a couple questions for you.
Now this is not a test,
it's not a quiz or anything
so don't shoot out answers.
Don't raise your hand
or anything like that.
But I'd like you to think
about these two questions.
I'll give you a few seconds, and come up
with an answer in your own head.
Whether you're right or
wrong, doesn't matter.
But we'll check it in just a few seconds.
Here we go.
("Think!" by Merv Griffin)
I can't play more of the
song 'cause copyright.
(laughing)
By the way, in case you didn't know,
the title of that little
song is called Think!.
(chuckling)
Okay, so two questions.
Everybody have some answers?
Yeah?
Okay.
Well, the first one is particularly easy
since I numbered them for you.
There are three declarations.
Now you may think that the
answer to the second question
is the same but it's not.
There are two names that
are being introduced.
You can think of them as
mangled names if you prefer.
But the specialization does
not introduce a new name.
It reuses an existing name.
You can't provide a specialization
unless you've already
provided the primary template.
So there's not a new name.
So you've got two names
that are being introduced
like you have three declarations.
We'll revisit this a little bit later on.
Let's look at the same
example a second time
and I have some different
questions for you.
What happens when you call g?
And here are some samples
for you to think about.
What happens if you call it with an int,
with a double, with a char,
with an array of char?
Make up your own type, std string.
What happens if you call?
Alright, here are the questions.
How many function declarations,
remember technically signatures,
but how many declarations
will be candidates
for the compiler's overload
resolution algorithm?
How many candidates will there be?
And of course, what are they?
Okay, please take a few
seconds and then we'll review.
("Think!" by Merv Griffin)
Okay, everybody got some answers?
Doesn't matter if you're right or wrong,
you'll remember it better
if you've tried it first.
Alright, here's the spoiler.
The same three declarations,
and I've given you
a clue up there, I've
taken away the numbers
and provided you with check mark.
The answer is that there will
be at most two candidates.
Now technically, I have to say at most
'cause there's some corner
cases where there's only one
but typically there will be two.
And what are they?
Well, here's the easy one.
Certainly, the ordinary
function goes into the mix.
It's a candidate.
It's even a viable candidate, for example,
it's got the right number of
function parameters, right?
So that's a candidate.
What's the other candidate?
It's a synthesized function declaration
that looks like that.
And I hope you're almost
immediately saying,
what the dickens is D?
Well, D is something that the
compiler has to figure out.
Okay?
It's usually deduced when the
compiler inspects the call.
Remember this all starts with
somebody writing a call to g.
If there's no call to g, there's no reason
for the compiler to do any of this.
Alright, so there's a call to g.
That call has some
function arguments in it.
The compiler can inspect them
and do some type deduction.
And I'll actually have some
extra slides on that topic.
I won't have time to go through them today
but if you download the
slides once they're available
from CppCon's website, you'll
find some extras slides.
If you notice, the slide numbers
might not always be contiguous.
That's 'cause there's some missing slides
in a couple places,
they're just hidden, okay?
So that type D will be
deduced by the compiler
by looking at the type of the
function argument in the call.
Then the compiler copies the declaration
of the function template and substitutes
for the placeholder, the
template parameter T,
its deduction for D.
Every place that there
is a T, it'll replace it
with whatever its figured out,
which I've here labeled D.
Okay?
And if you never need to ensure
that's that particular
substitution takes place,
you can always write it
as shown on the last line
and that forces, you know, it says,
compiler don't waste your
time deducing, do it this way.
Okay?
And sometimes you want
to do that in a call.
If you want to ensure that
a particular specialization
gets called, you can force it by putting
in your own type there as a substitution
for the template parameter.
Now a lot of people are puzzled.
They say, well, why is the
template itself not a candidate?
The answer is actually to be surprisingly,
turns out to be surprisingly simple.
Remember, templates don't
have function-like behavior,
as I said earlier, you
can't call a template.
So why consider it as a candidate?
You can never pick it,
can't call it, right?
Templates are not function and they're not
any other kind of callable entity.
And there are lots of things you can call.
You can call with a function pointer.
You can call with objects that
have an operative parents.
You know, function objects and so,
there are lots of things
that you can call.
A function template is
none of those things.
You can't call it.
Therefore templates are never candidates
for overload resolution.
Now, here's another way to think about it,
for those of you who are visual thinkers.
A cookie cutter is like
a function template.
And if you speak British English,
we're talking about biscuit cutters.
Okay?
The cookie dough is
like template arguments.
You put those two things
together and you get a cookie.
In our case, a function.
And of course, use different dough,
you get a different kind of cookie.
And that analogy will take you
surprisingly far by the way.
I've taught like teenagers
about functions templates
by appealing to this picture
and they get it, okay?
So feel free to use this.
Alright, so why really can't
you call a function template?
Would you try to eat the cookie cutter?
(chuckling)
I don't that'll taste very good.
Alright, a cookie cutter isn't edible
'cause it's not a cookie.
A function template isn't callable
'cause it's not a function.
It's something else, right?
So, a template can never be a candidate
but since we can use cookie cutters
plus cookie dough to make cookies,
we can use function templates
plus function template
arguments to make functions,
and of course the point
is that the compiler
will do that for us.
The compiler will synthesize
a function declaration
from that primary function
template declaration.
But remember, it first inspects the call,
deduces the types necessary by looking
at the function arguments in the call,
uses the results of that deduction
and substitutes as appropriate
for the placeholders
which are the template parameters.
And the net result is that you get
a synthesized candidate
for overload resolution.
Now overload resolution is
just gonna do its normal thing.
Among the very first things
overload resolution does
is look at all the possible
candidates and say,
which ones are just not viable?
For example, it has the wrong
number of function parameters.
Well, that can't possibly be chosen
so that gets thrown
out almost immediately.
But that's part of overload resolution.
That's got nothing to do with the fact
that we're dealing with
template specializations here.
Sorry, synthesized declarations.
Alright, so the other question I get asked
from this example is, okay,
but we have this explicit
specialization sitting there.
How come that's not a candidate?
Because this is a function right?
Specialization is a function.
Doesn't matter if the compiler produces it
or if you produce it explicitly.
It's a function.
So why is that not a candidate
for overload resolution?
Well, it doesn't work that way.
It's a declaration but remember,
there are declarations
that don't introduce names.
For most programmers, it's sort of,
you know, you ask them
like a trivial question.
True or false, you write
declarations to introduce names.
And almost everybody will say yep,
that's what you do it.
That's what the purpose is.
And that's just not quite true.
There are declarations that
do not introduce new names.
My favorite example is static assert.
Not many C++ programmers know this
but if you look at the grammar,
static assert is a declaration.
It sure doesn't introduce
any new names, right?
Also, we all know that you
can re-declare something,
as often as you like.
That doesn't introduce a new name.
It recycles an existing name.
You're re-declaring it, in the same way.
Now, of more interest to us,
the standard very clearly says,
and there's the reference
if you wanna go look it up,
an explicit specialization of a template
does not introduce a name.
And that's the reason that specializations
don't take part in overload resolution.
Okay?
And this is key.
I suspect that the vast
majority of C++ programmers
would intuit that if you write
an explicit specialization,
of course it'll be considered
an overload resolution
and if it fits, it's gonna be picked.
It's not the way it works.
Specializations are never candidates
for overload resolution.
If you take away nothing else
from this talk, that's the key.
Specializations do not participate
in overload resolution.
Okay.
So, we've talked about declarations,
candidates for overload resolution.
At some point, you
actually need a function
to be compiled.
So where is that?
Well, suppose we've gone
through overload resolution
and we've picked one of the candidates
from that particular class.
Sorry, from that particular
function template.
So for example, if the call says, g of 42
then that specialization, sorry,
that declaration will be
synthesized if the call
is g of character, a different declaration
will be synthesized.
Alright, so suppose we've actually gone
through overload resolution
and we've picked such a declaration.
Now we need a definition, right?
Notice, don't need any
definitions until now.
Overload resolution does
not look at definitions.
It looks only at declarations, okay?
So there are two cases.
Case one, there might be a
preexisting specialization
of that template, such
that its template arguments
match the ones of the chosen candidate.
Now that can come about in
at least two different ways.
There might be an explicit
specialization like that
or an equivalent call might
have been encountered previously
and the compiler has already instantiated
that specialization.
So if there is an appropriate,
pre-existing specialization,
then that specialization
is going to be compiled.
And maybe already has.
And then ultimately, of
course, that's the one
that'll be called later.
Case two, of course, is otherwise.
There is no preexisting specialization
so the compiler now has to instantiate one
that matches, et cetera.
And how does it do that?
It replicates the definition
from the primary template,
does the appropriate substitution.
Notice, it doesn't have
to figure it out again.
That's already happened, when
it picked the declaration.
Now it carries through
that same substitution
in the definition and now
we have a specialization
that's ready to be compiled.
That's the function that'll be compiled,
will show up in the object file
and is going to be called
when the program runs, okay?
So those are the main important steps.
Now, there's some interesting situations
that you can get into.
Suppose you have more
than one function template
by the same name, yes, function templates
can overload each other, as
well as ordinary functions.
So imagine you have multiple
templates all by the same name
and each one can give you a
candidate for a particular call.
Compiler has to pick one, if it can.
So as part of overload resolution,
you might wanna think of
this as a separate step
or you might wanna
think of it as a substep
of overload resolution but
at the appropriate point,
there's this algorithm
called partial ordering
of function templates.
And it's a non-trivial algorithm
but the point is to
handle cases like this.
And it's called partial ordering
because sometimes the
compiler just can't pick one.
There's no reason to
prefer one over the other.
The objective is to pick, and the phrase
is the most specialized
of the viable templates
or candidates, right?
You wanna pick one, and the criterion
is which is the most specialized?
If only two, you say more specialized
but, alright, in general,
it's the most specialized.
So here's a specific example.
Suppose you have one function template
that has a function parameter of type T
and the second function
template, the overload,
has a function parameter
of type pointer to T, 'kay?
And suppose we have a call
with a function argument
of some pointer type.
I don't care what the value is.
Just think about the type.
It's some pointer type.
Maybe it's int star or double
star, doesn't matter, okay?
It turns out that the function template
that has a function
parameter of type T star
is considered more specialized
than the other one.
Even though both are otherwise
viable matches, okay?
And without going into
the algorithm in detail,
the upshot is the compiler
tries it both ways.
If I do it this way, can
the other one still work?
If I do it the other way,
can this one still work?
And it turns out you can
only do that in one direction
and so it picks the one
that's more specialized.
Now, here's a chance for you
to show off what you know.
Again, don't shout out anything,
don't raise your hand but let's
look at a different example.
Alright?
And by now, you can all
tell what these things are.
I've labeled them for
reference; a, b and c.
And the question for you to resolve is,
given these two statements,
which h is gonna be called?
("Think!" by Merv Griffin)
I'll give you a few extra seconds.
This is not quite as easy as before.
Yes, this is really is legal code.
You can do this.
Now we can argue all day as
to whether you should do this
but you can do this.
'Kay, you ready for the answer?
Everybody got an answer?
Alright.
It's gonna call a specialization of c.
Now if you find that surprising,
let's go through it in
a little bit of detail.
Always ask the question,
what are the candidates
that will be considered
for overload resolution?
And there are two.
You have a candidate from template a
and you have a candidate
contributed by template c.
B does not factor into overload resolution
because it's an explicit specialization.
See the empty angle brackets.
You have to ignore that
for the time being.
So the issue is, which of the candidates
is more specialized?
And the answer is c.
Exactly as we explained
on the previous page.
Do notice, and perhaps
you'll be surprised by this,
the explicit specialization, b,
it's a specialization of template a.
It can't be a specialization
of template c.
And the reason for that is
like Computer Science 101.
Introductory course.
At the point that the compiler
sees that specialization,
the only declaration of g that
it has previously seen is a.
It's the only one that's in scope.
There's no look-ahead, right?
'Kay, so the only possible candidate
that b could be a specialization of is a.
Oh wait, I used the word candidate.
That's a different kind of candidate.
When the compiler sees a specialization,
it has to say, okay, I see
that it's a specialization but of what?
So there's a form of overload
resolution that kicks in here.
Overload resolution does not only apply
when there are function calls.
There are other
circumstances for other forms
of overload resolution, okay?
And this is one of them.
Here's an explicit specialization,
to which primary template does it belong?
What template does it specialize?
And here's it easy 'cause
there's only one candidate.
Eh, let's change the example a little bit.
Same declarations, slight rearrangement.
Same question, go.
("Think!" by Merv Griffin)
'Kay, I'm seeing some light
bulbs going on in people's eyes.
Okay, ready for the answer, good.
It's going to call b.
'Kay?
So what changed?
All I did was move b down one line.
What changed?
When the compiler figures
out which template,
of which template is b a specialization,
it has to consider both a and c.
They're both in scope.
Alright?
Partial ordering kicks in.
And it's going to pick c
as the primary template
that corresponds to the
explicit specialization b.
Now when it comes to
figuring out what to call,
it's still a versus c,
and for exactly the
same reasons as before,
it's going to pick the
specialization, sorry,
it's going to pick the
declaration synthesized from c.
That has not changed
from the previous page.
What has changed is, there is already
an existing specialization.
Namely b and that's why b gets called.
Okay?
One more just for kicks.
Put 'em back in the same
order and throw in d.
Look at the declarations of b and d.
Don't they look similar?
Except, of course, for the
body which I haven't shown you.
Is this still legal code, and if so,
now what's gonna get called?
Go.
("Think!" by Merv Griffin)
I'll give you a little
extra time on this one.
I see some people nodding their heads.
Are we ready?
Yeah, okay.
No, okay, I'll give you a
few more seconds, one second.
Alright, here we go.
We're gonna call d.
D as in dog.
Work out where the
specializations come from.
B as in boy is still an
explicit specialization of a
'cause that's the only one
that's in scope at that point.
D as in dog is an explicit
specialization of c.
Both a and c are in scope and
for the exact same reasons
we discussed on the previous page,
the compiler figures out
that d belongs with c.
Now we get synthesized
candidates from a and c as before
and c is still chosen
and we have a matching
explicit specialization and that's d.
So we're gonna end up calling d.
What is kind of interesting
is the substitutions.
In the case of specialization b,
the template parameter T from the primary,
it's replaced by pointer to int.
In the second specialization,
the template parameter T
is replaced only by int.
Why?
Because the star, the asterisk,
is already part of the function parameter.
Alright, deduction happens on the basis
of function parameters
and function arguments.
Okay.
Alright, so having gone through that,
let's return to the topic
of explicit specializations.
Using explicit specialization
as a form of customization
for function templates is considered
by many, many programmers to
be not a good thing to do.
And by the way, this is
not a new development.
This has been known for
at least 20 some years.
You should avoid this if at all possible.
It's wrong to use function
template specialization
because it interacts in
bad ways with overloads.
Overload resolution does
not take into account
explicit specialization
of function templates.
Most programmers believe the opposite
and it's simply wrong, that's
not how specializations work.
Okay?
Explicit specializations are not part
of overload resolution.
Only after overload
resolution has made a choice,
will any explicit
specializations be considered.
Okay?
Now this has been known for a long time
but I've discovered it's
not particularly well-known.
So, please go forth and evangelize.
So here's some advice.
Avoid it.
Avoid writing explicit specializations
of function templates.
Please remember, I'm talking
about function templates.
There are other kinds of templates.
This advice does not apply there.
It's function templates
that you can overload,
not those other kinds of templates, right?
If you do need to customize
your function template,
just write an ordinary
function by the same name
with whatever arguments you want, okay?
Sorry, with whatever parameters you want.
If you have to specialize,
do it indirectly.
So the starting point to just to recall
that class templates
can't overload, right?
Types don't overload.
Okay, so we can take
advantage of that fact.
Invent a helper class template
with an apply operator,
call operator if you prefer.
Specialize that one to
your heart's content, 'kay?
And then write the
original function template
so all it does is forward the call
to the class templates operator parents.
And all the special logic
takes place in the class.
Yes it's one level of indirection
but it gets you around all of the issues
involving function
template specialization.
You also get some other things for free.
It's not on topic for this talk
but there is such a thing
as partial specialization.
It does not apply to function templates.
It does apply, for
example, to class templates
and variable templates, et cetera, okay?
Thank you, Robert Heinlein.
Yeah, it's for compilers to do.
Not so much for us programmers.
So what's in store?
Well, I want to talk about two proposals
that are going to be before
the standardization committee
at the upcoming meeting in November
which will be held in
San Diego, California.
I don't know what will happen
with either of these proposals.
One is a little bit farther advanced
than the other one but
neither has been voted in
to the next C++ working paper.
In the standard library, for a long time,
we have allowed programmers
to provide explicit specializations
of the function templates that constitute
so much of the standard library.
There are an awful lot
of function templates
in the standard library,
like almost everything
in the algorithm center.
And a whole lot of others.
Utilities headers got lots
of function templates in it.
Even utilities like move and
forward are function templates.
Technically, you could specialize those.
This is nightmare for those of us
who write the standard library.
It's a nightmare to
take that into account.
Imagine calling std forward
and having it do something different.
And not knowing, oops.
So, permission to do
that is being withdrawn.
Yeah, I had a little
something to do with that.
And the words are on route
and I think this is going to happen.
But there are still cases where you want
to specialize somehow.
Well, customize, okay?
So some algorithms are
going to be respecified.
This is not yet happened,
but as I say, it's on route.
And what they will become will be called
customization point objects.
Now you know that you can
call a function object
as if it were a function
so from the call side,
you can't tell the difference.
But there is a technical difference.
We will allow you to write
your own customizations
just by writing your
own ordinary function.
Don't do anything with function templates.
Just customize by writing
your own function.
For example, you have a type
and it has a particularly
efficient way of swapping.
Go ahead and write your own swap function.
It does whatever's
necessary for your type.
But do it in your name
space, stay out of std.
Okay?
And it's gonna work.
We know how to do this.
We've known how to do this
for several years now.
As a bonus, you'll be able to call swap
either qualified or unqualified.
And I mean std qualified, right?
You call std swap.
It'll find your function
if that's the best match.
Okay?
As I said, we know how to make this work.
If you're curious, there's
a paper by Eric Niebler
of about three or four years ago.
He lays how to do it.
C++ 17, we can do it still better
because we have some new features
in the language like inline
variables and things like that.
So we can do it better.
But we know how to make this work.
And if you are an author of generic code,
until now, you have to
do what a lot of us call
the two step dance, right?
If there might be a
specialization somewhere,
first you have to bring the swap
from the standard name space into scope
and then call unqualified
and that overload resolution will kick in.
That's what you have to do today.
You won't have to do that in the future.
This will do the right
thing, this will just work.
So programmers will have far fewer reasons
to put stuff into std.
As I say, those of us who
write standard library code,
it'll make our life a
lot easier, trust me.
Okay?
So that's number one.
There's also a proposal
up for consideration
at the next meeting that
involves the core language.
Not the library.
So we're looking at ways
to write function templates
using a simpler syntax, okay?
So this ties into Biernas
talk from this morning.
I hope you were there and listened to it.
We can already do this
because we have return type deduction.
We've had that for a
number of years right?
But this is just an
ordinary function template
that you can write today.
But instead of having to use
the keyword template on a declaration,
we're thinking about
letting you write auto
as the key to the compiler that says,
okay, you figure out the right type.
And if you wanna reference,
you can write auto ref
or auto const ref and whatever,
and it'll do the right deduction.
But it assumes you don't have
to name the type anywhere else.
But if this is sufficient
and surprisingly often it is,
then this is a simpler way of writing it.
As I say, under consideration.
No guarantees.
What's interesting is
that this is intended
to work with what we are calling
constrained declarations.
The long form of constrained declaration
is one that has a requires clause in it.
Okay?
And you can write this
today, if you enable,
if you use GCC, you turn on, what is it?
Dash f concepts, I think it is.
This works today, okay?
I'm assuming you have a
concept named sortable.
This is way Stepanov has always envisioned
how it should work.
You go back to his early
work, 20 some years ago,
this is what he writes.
Go online and listen to the
talks he gave before he retired.
I mean, set aside like a week or two
'cause there are a lot of them.
But they're well worth it.
I recommend them highly.
But this looks to be on route for C++ 20.
And what's being proposed now
is tentatively being
termed adjective syntax.
Which may or may not make it into C++ 20.
We have not yet considered it.
This is a fairly recent paper
but a lot of people think
it shows some promise
and I think it'll be given
serious consideration.
'Kay?
Alright so, what have we
not talked about today?
If you're getting in to templates,
obviously you have a couple
directions to go and learn more.
Class templates, alias
templates in C++ 11.
Variable templates in C++ 14.
Templates that have more
than one template parameter
'cause there are opportunities
for interactions there.
Okay.
Templates that involve parameter packs,
that involve other kinds
of template parameters,
like non-type template parameter
or template template parameter.
Yes, a template parameter
that is a template.
If that confuses you,
think of it as a call back.
Think of it as declaring a call back.
Okay?
It works.
Something new in C++ 17 called
class template argument deduction.
Before C++ 17, if you
wanted a vector of int,
you always had to say
vector angle bracket int.
In C++ 17, you can leave
off the angle brackets
and just say vector if
you provide an initializer
for your variable and the compiler
can deduce the right type by
inspecting the initializer.
It's called class template
argument deduction.
One of the best things
in C++ 17, terrific.
I had very little to do with it
but I was involved just a bit.
There's template metaprogramming.
If you wanna follow up on that,
I'll refer you first to the video
of my talks from the
first CppCon back in 2014.
We now have constrained templates.
Since the concepts TS
and likely in C++ 20.
And above all, if you really
want to understand templates,
I highly recommend this
book, second edition,
by Vandevoorde, Josuttis and by Gregor.
Consider it the Bible as far
as anything to do with templates.
Thank you all very much.
(audience clapping)
We have few minutes if
there are questions.
What I would ask, if you would be so kind,
there's a microphone over
here and that way they
can capture your voice
for posterity, I guess.
Sorry to make you walk, they only set up
one microphone in this room.
Sir.
- Hi.
You meant, the upcoming stuff,
I guess, was pretty general.
I just had like one specific question,
I guess about function templates
so one of my least
favorite two step dances
with function templates are index sequence
because you just always have to create
like an underscore impl
function as far as I know.
And you know, like create it and pass it
and then it gets deduced and so on.
Is there any plan to not have
to do that two step dance anymore?
- I am unaware of any
proposal that addresses that.
- Okay.
- Would you like to write one?
(laughing)
- I don't think I know enough
but you know.
- I'll help.
- Okay, deal (laughing), thanks.
- Send me e-mail.
Thank you.
Sir.
- I believe the two step
dance you were talking about
involves using ADL to
decide what swap to do.
The one outside the standard names base.
Does the new thing being
proposed also use ADL
or generalize it or is it
something completely different?
- ADL is involved but
less overtly than before.
- Okay, thank you.
- You're welcome.
If you're interested in the details,
I'd highly recommend, I think there's also
a blog by Eric that sets out some of it.
I'm not sure but I know there's a paper
that goes back a few
years in which he sets out
the technology of that era.
But we now know how to do it even better.
Thank you.
Sir.
- In the example you have on slide 22,
I had a question about the
arrangement of the templates.
Is there any way --
- That would be this?
- Yes.
- Okay, let me study it again, okay, yes?
- Is there any way once all
four of these declarations
have been seen, to call b?
Is it callable by any possible mechanism?
- Yes.
You can provide, remember
the explicit notation.
You fill in the angle brackets
and deduction is turned off.
- [Attendee] But if you
pass in the angle brackets,
int star, aren't you going to get d?
- No, because that would be int star star.
(audience mumbling)
I'm going backwards, sorry.
I shouldn't answer questions
like this on the fly.
I think the answer is yes.
I think that's the right way to do it.
I may have the details wrong right now.
- [Attendee] Okay.
- But let's talk offline if you like.
- [Attendee] Sounds good.
- Okay, yeah, thanks.
Yes sir.
- So I don't remember
which slide number it was
but on one of them, you
suggested using a class template.
- Ah yes.
Yes, yes, yes.
- And I was wondering what the trade offs
are between having a function
that forwards to that
versus a template variable of the type
of the function object.
- I believe you're referring
to this slide, yes?
- [Attendee] Yes.
I was wondering what the
trade offs are there.
- Which kind of, are you
talking about performance?
Or compiled time or what --
- Developer's sanity, mainly.
(audience laughing)
- I'm sorry?
- Developer's sanity, mainly.
- Oh, but forwarding is
a time honored technique.
We've been doing this
for decades at least.
So, you know, this doesn't even come close
to insane on the level
of code that I've seen.
(laughing)
- [Attendee] Now that we
have variable templates,
does that change that, what
you would recommend at all?
- Variable templates are
actually a special case
of class templates.
Talking about a class template
that has a static number variable.
You now have variable templates, right?
And I think that's how it implemented.
And by the way, in case you're curious,
the way we got variable
templates in the standard,
we struck out a line
(audience chuckling)
and suddenly they worked.
I think that was the extent of the change
to the wording of the standard.
We took out ao restriction.
And then we got variable templates.
So maybe a little bit but I
think not significantly, no.
- Okay.
- Thank you.
Yes sir.
- Hi.
- One more question.
- Last one.
So when you talk with
function templates here,
are you also including
the function templates
in a class that same
overload resolution apply?
- I believe what you're discussing
is usually called member
function templates.
- Yes.
- I believe the answer is yes.
But now you have an extra
scope to worry about.
- I'm just saying, within the class scope.
- Within, it works just fine.
If you wanna drive yourself crazy,
have a member function template
that's a member of a class template.
(chuckling)
'Cause now you have two
sets of template arguments.
One for the type and one for the function.
But it works and there are
good use cases for all of that.
- Yeah, I don't think you
would fully specialize
a member function template.
- It is possible.
- But I'm sure it's possible --
- It is possible to do.
- I'm just saying,
does your rules apply to
that overload resolution set
on a member function set?
- I'm not persuaded that you're right
but we can talk about
that more if you like.
Thank you.
Alright, thank you all very much.
(clapping)
Thank you.
