CppCast - Regular Void
Episode Date: December 21, 2016Rob and Jason are joined by Matt Calabrese to talk about his Regular Void Proposal, template<auto>, the state of Concepts and more. Matt Calabrese is a software engineer working primaril...y in C++. He started his programming career in the game industry and is now working on libraries at Google. Matt has been active in the Boost community for over a decade, is currently a member of the Boost Steering Committee, and is a member of the Program Committee for C++Now. Starting in the fall of 2015, he has been attending C++ Standards Committee meetings, authoring several proposals targeting the standard after C++17, notably including a proposal to turn the void type into an instantiable type and a proposal for the standard library to introduce a generic algorithm for invoking standard Callables with argument types and argument amounts that may be partially calculated at compile-time or at runtime. He is also the author of the controversial paper "Why I want Concepts, but why they should come later rather than sooner", which may have contributed to the decision to not include the concepts language feature in C++17. News 2016 Software Developer Podcast Awards My take at times A C++ program to get CPU usage from command line in Linux Pointer comparison an invalid optimization in GCC Matt Calabrese @cppsage Links Boost C++Now P0146: Regular Void (Revision 1) P0376: A Single Generalization of std::invoke, std::apply, and std::visit P0240: Why I want Concepts, but why they should come later rather than sooner Sponsor Backtrace
Transcript
Discussion (0)
This episode of CppCast is sponsored by Backtrace, the turnkey debugging platform that helps you
spend less time debugging and more time building. Get to the root cause quickly with detailed
information at your fingertips. Start your free trial at backtrace.io slash cppcast.
Episode 83 of CppCast with guest Matt Calabrese recorded December 21st, 2016.
In this episode, we discuss the 2016 Software Developer Podcast Awards.
Then we talk to Matt Calabrese,
member of the C++ Standards Committee.
Matt talks to us about his regular void proposal and more. Welcome to episode 83 of CppCast, the only podcast for C++ developers by C++ developers.
I'm your host, Rob Irving, joined by my co-host, Jason Turner.
Jason, how are you doing today?
Pretty good, Rob. How about you?
Doing good. Looking forward to the holiday season coming up.
This will be our last episode for the year.
Yeah.
Really?
We'll be back in January, right?
Yes.
Yeah.
We're taking off next week, but we will be back.
And we actually still need to line up some guests, but I'm sure that won't be too difficult, right?
No, it shouldn't be a problem. and yeah i'm curious so this is a sunday to sunday holiday
week which is a little unusual yeah are you taking off the whole week uh i am going to be
taking off all of next week gonna be traveling up to lovely new jersey to see my family yeah i'm just wondering if lovely was meant sarcastically a little yeah okay um
well it's our episode i'd like to read a piece of feedback um this week uh hopefully i can
pronounce this right gisline writes in saying hello uh first good job on the show i listened
to it in my commutes to and from work and i look
forward to it every week i want to make a suggestion for a subject it's unfortunately
pretty broad and probably not that useful but anyway here it goes i think it would be nice to
have something about c++ in the medical field i personally work in radiation therapy as a physicist
and know that computers are now heavily used in the medical field but i don't know what place c++
has in that field would have been nice to find medical field, but I don't know what place C++ has in that field,
would have been nice to find out.
As a more precise suggestion, I know of the DCMTK library.
Maybe someone from that library would have the time to be a guest on the show
and discuss where this library is headed and how much it's used and such.
Anyway, congrats on the show and nice holidays to you both.
So thank you, Ghislaine.
Yeah, I'm not too sure about the use of C++ in the
medical field, but I would assume that a lot of the, you know, machinery and diagnostic equipment
might be powered by C++, right? Yeah, I actually know a few people in the medical devices industry
who use C++. And there's two or three companies just here in Colorado
that are medical devices.
Well, maybe you might know someone
who would be a good guest for that topic.
I know some people.
I don't know how much they would be able
to talk about what they do.
Right.
But I could look into it.
Yeah.
Okay.
Yeah, it's something we'll look into.
Well, we'd love to hear your thoughts
about the show as well.
You can always reach out to us
on Facebook, Twitter, or email us at feedback at cppcast.com. And don't forget to leave us a review
on iTunes. Joining us today is Matt Calabrese. Matt is a software engineer working primarily in
C++. He started his programming career in the game industry and is now working on libraries at Google.
Matt has been active in the Boost community for over a decade, is currently a member of the Boost
steering committee, and is a member of the program committee for C++ Now.
Starting in the fall of 2015, he's been attending C++ Standards Committee meetings,
authoring several proposals targeting the standard after C++ 17, notably including a proposal to turn
the void type into an instantiable type and a proposal for the standard library to introduce
a generic algorithm for invoking standard callables with argument types and argument amounts that may be partially calculated
at compile time or at runtime. He's also the author of the controversial paper,
Why I Want Concepts, But Why They Should Come Later Rather Than Sooner, which may have
contributed to the decision to not include the concepts language feature in C++17.
Matt, welcome to the show.
Hi, thanks. Thanks for having me.
So you've made an interesting switch in your career here. It seems like there's so many
programmers that are like, I want to program in games. And you did games, and you're like,
enough of that. Now I'm going to work on libraries. So I'm curious how that went.
Well, I've always kind of worked in libraries. But the game industry thing is just, like you said,
a lot of people just, oh, they would love to work in games,
they'd love to work in games,
but when you actually get into the industry,
you realize that it's not quite as fun,
or at least I didn't find it quite as fun
as all the library development that I'd done in the past.
So even when I got in the game industry,
I was already participating in the Boost community,
I'd written a bunch of generic libraries,
and that was more kind of my thing, and that's not quite as embraced in the game industry i was already participating in the boost community and written a bunch of generic libraries and that was more kind of my thing
and that's not quite as embraced in the in the game industry so
so you said it's not as much fun as you might think did you
was there like the crunch culture or whatever the people you're always
it's always crunch time it feels like you're always accumulating technical
debt and that could be just the experience it feels like you're always accumulating technical debt.
That could be just the experience that I had.
I was at a THQ studio,
and I joined late in the development process of a game,
and maybe that was just a symptom of that.
Another thing I've heard about,
at least with the AAA game studios,
is that you're just working on one piece and always improving the performance of it, improving capabilities of it, but you're not really
working on a game as much as just this one tiny piece of the game, right?
Yeah, that's true.
And like what I was doing when I was at the THQ studio is I was doing a lot of tools development
and making like the world editor, things like that.
So yeah, you really only see a small part.
It's like, yeah, technically I was working on a game, but it doesn't feel like it when you're doing it quite as much.
I imagine in smaller studios where you're actually maybe like three or four people or something,
but here we had, I forget how many programmers.
It was definitely multiple, maybe like 40, 50 or more.
Wow. I've never worked on a team that big, even that big, yeah.
Okay, Matt. Well,
we got a couple articles to discuss and feel free to jump in on any of these
and then we'll start talking to you about the void proposal and some other
work you've been doing. Okay. Okay.
So this first one is the 2016 software developer podcast awards.
And this award thing is kind of a new idea that um john sonmez put out he is a fairly popular
programming blogger he's got simpleprogrammer.com and for a couple years now actually he's
maintained this blog post as a list of different software development podcasts and i'm proud to
say that cppcastast is listed there.
It is listed as the one and only C++ podcast, which is great.
And he decided that he would kind of make an award out of this list
because he's got multiple Java podcasts, multiple Microsoft podcasts,
multiple JavaScript podcasts.
So he's letting people vote on these different categories.
And I think there's going to be like two rounds of voting
where all the winners from the first round
from these different subcategories
will then compete as just the best podcast.
So please take a look at this link.
You do not have to vote for every category,
which would be kind of silly
because I have no idea what these different JavaScript podcasts are, so I wouldn't know which one to vote for is the best.
But you can vote for whichever category you're interested in.
So you could vote for us, and if there's other software-related podcasts, you might find them on the list and vote for them as well.
I will say we are definitely hoping to win the C++ podcast category.
We got some pretty stiff competition, right, Jason?
Yes.
Yeah, we are the only one listed under best C++ podcast,
which I was a little surprised by because right under us is best miscellaneous language podcast. And in there, there just seem to be other podcasts that maybe don't have enough entries for their own category.
Right.
So why are we not in them?
Elixir.
I think Elixir is a programming language, right?
I don't know.
I'm not exactly sure what that is.
But I'm not sure why he decided to put us into our own categories instead of doing the best miscellaneous language, but I'll take it.
Yeah, but some of these things are shocking, like 20-some-odd in JavaScript category.
Yeah, there are a lot of JavaScript podcasts.
Five PHP podcasts.
Five PHP.
I'm looking at seven.NET Microsoft-related podcasts, four for Java.
Yeah, there's a lot of programming podcasts out
there you know i'm thinking maybe we're not in the general or whatever um miscellaneous language
because all those if you look at the language itself they're small rarely used languages
that could be maybe it's more commentary on the language not on the podcast yeah that would
make sense yeah because definitely c++ deserves to have its own category like like java and dotnet
and those other ones too yeah yeah okay uh this next one is kind of a follow-up to one of the
articles we talked about last week with the c++ version of Ruby's integer times. And John Kolb decided to take his
own stab at implementing this type of functionality. Only he didn't want to do the Ruby style syntax of
42 dot times or underscore times. And in the case of that blog post, you wanted to just make a pure function that would take a number
and take a callable function pointer or lambda
and be able to execute it multiple times
based on the number.
What are your thoughts about this, Jason?
I think it's a good article,
and I think there's probably something
for most C++ programmers to learn from reading this.
Some SphinA tricks to decide
which version of times to call
and some other
tricks
on making it more general further down.
Yeah, and he
made a much more complex
version of it because his allows you to
say, I want to do from
10 to 20
incrementing in units of five instead of just one
so you can get a lot more complex with his version of it yeah yeah i thought i just saw a bug but i
think i was wrong uh next one uh a c++ program to get cpu usage from the command line in linux
is this something you think you would make use of, Jason?
It is the kind of thing I have done before. The official way to get
these things is from the proc file system, as he's showing here, or
he or she, whoever wrote the article.
It's kind of mostly about parsing
files, the proc stat file.
But it's still an interesting read, yeah.
And this next one is about pointer comparison
and how this author thinks GCC is making an invalid optimization
and that you can basically compare two pointers and even if they should be equal
is his argument gcc will say they are not and i think he's got a pretty good argument i mean
it makes sense to me so matt did you look at this one unfortunately i did not look at this i i skimmed it a while ago and i skimmed it just
before uh we started recording and uh yeah i i'm i'm not enough of a language lawyer to really uh
be able to analyze it enough to say one way or the other i did shoot an email to uh somebody
in the standards committee about it though to see what their response would be okay so it's quoting
the c standard as opposed to the c++, so it could be different.
It is.
Right.
So the point that he makes,
let's see if I can find it real quick.
Both pointers, two pointers can be considered the same,
and there's an explicit wording that says,
one is a pointer to one past the end of one array object,
and the other is a pointer to the start of a different array object
that happens to immediately follow the first array object in the address space
so he puts two arrays adjacent to each other compares the two pointers one past the end of
the first one the one at the beginning of the second one and it returns false that when you
turn on optimization but someone down in a comment points out,
and I don't, obviously,
I'm not a language layer enough to understand this either,
but they point out that his example is using the stack.
There are arrays in main on the stack.
But if you were to put those two arrays inside a struct
where the memory model guarantees
that they are actually adjacent to each other,
then GCC does not perform the optimization that he thinks is invalid.
So there you go.
Interesting.
Well, I'll definitely need, I guess, a language lawyer's opinion on this.
In most contexts, I would consider myself a language lawyer, but not here.
Okay. Well, Matt, let's start talking about the regular void proposal.
What exactly is the point of this proposal?
Okay. So the point of regular void is, well, it has two points. The first point,
which is like the main motivation is that when you're writing generic code,
very often you want whatever
your code is templated on to work equally well with void as it would with other types. A good
example where this comes up in the standard library, it's a symptom of the fact that void is
not regular, is we have like these specializations for std promise and std future for the void type,
where if you want to, for instance, execute a function asynchronously
and get back a future to the result type, you want to be able to do that with void just as
easily as you can with other types. Like if your function had returned an int, it would work
perfectly fine. Why doesn't it work perfectly fine for void? And the answer is we force it to work
in the standard library by just creating a specialization with a slightly different interface,
just so that way you get a similar type of functionality. So the goal of this proposal
is to just make it so that void is like all the other types that we have in the language,
all the other regular types that we have in the language, so that you don't need these types of
specializations for std promise, std future. The proposed std expected also has a special case for void. The proposed stood variant,
which is now in CBLSW 17, for a while had special casing for void, but we actually just cut it out
at the last standards meeting. So it's definitely a problem that a lot of people encounter,
both inside and outside of the standards committee. And so this just seems like the
best way to make it work. And so I use the word regular a bunch of times,
and I realized I never actually defined it.
So when I say I want void to be a regular type,
the term regular comes from the generic programming community.
And it basically means that your type is well-behaved with value semantics.
And by that, I mean it can be copied and moved around.
A copy and an assignment both result in a separate object
that has an equivalent value to the original object
and they have this property called substitutability
where if you have a function and you call it with one value,
you're able to call it with a copy of the same value,
and you'll get back the same result.
So these are all just kind of properties that you expect out of things like ints, floats,
and any well behaved type that you would make on your own any well behaved user defined
type.
And so we just want to make void exactly the same.
And so in doing that, we basically just make void a monostate type.
So it can only ever have one value if you wanted to analyze it in that sense, we basically just make void a monostate type. So it can only ever
have one value if you wanted to analyze it in that sense. You can make an instance of it,
you can copy it around, you can return it from functions, you can even compare them,
they're always compare equal. And so that's just basically the general idea. And so in practice,
most people won't be using this, the people who take advantage of it are people who are just writing templates.
It just means that they don't have to make a special case for it,
or equivalently, if you're using a template and you don't want to special case it.
So to be clear, you're saying you would be able to create an object that is type of void,
or you could have like void space V semicolon, that would be valid code?
Yep, you would, you would be able to do it.
Yeah, I mean, so this is I'm saying you would be able to do that.
That's if my proposal goes through.
I'm currently on the second revision of it.
The first time I brought it to the standards committee,
it had kind of mixed results.
I came back, and it had very positive results.
And the head of EWG and myself agreed that before we went further,
I wanted to come back with an actual implementation in Clang and test it out with existing code bases, make sure nothing breaks.
But the whole point of the proposal is I try not to break anything at all.
And I've had it looked over by people in core, and they agree that it should be a perfectly valid change to make, and they don't foresee any problems.
It's not going to be an ABI break or anything. So I'm pretty confident that eventually I will be able to convince the remaining people who
hold out against the idea that it is in fact a good idea and a safe change to make. So I'm
hoping that by C++20, I'll be able to say that I was able to turn void into a regular type,
which would be pretty cool. So this concept came up on the CPP Slack when I was on there recently.
And before I forget, I promised them that I would ask,
what is the size of a void object?
Ah, so this is actually a really good question.
So in an ideal world, if we were designing C++ from scratch,
which unfortunately we're not,
it would be great if we could have size++ from scratch, which unfortunately we're not, it would be great
if we could have size of void be equal to zero. And one of the reasons why you want this is,
let's say you're writing generic code, and maybe you have a tuple of all of the results of function
calls, and the functions that you're calling happen to be dependent types. So in other words,
they're dependent on a template argument. In the case that those happen to return void or something like that, you don't want them to
actually occupy space in this tuple, you want them to logically occupy an element of that tuple,
but you don't want them to contribute to the overall amount of space that that object takes up.
And so ideally, that would be what we'd want. But unfortunately, because of existing language rules,
it's really difficult for me to actually make void equal to zero,
size of void equal to zero.
Some of the problems that you encounter are if size of void is zero
and you want to be able to take advantage of it in a way that makes it
so that it doesn't contribute to the overall size of an object,
then that means that you eventually end up with cases where you'd have two void objects that occupy the same address in memory.
And so this is one particular kind of problem.
Like, normally when you have objects in C++, if you have two distinct objects of the same type, they can't share an address. So this is kind of like what I consider a minor problem with having size of void be
zero, but it would be a difference from other types that we have in the language.
And that can potentially manifest itself in generic code if you're relying on this property
of all object types occupying different addresses.
But the more troubling one that I find is if you have size of void equal to zero and you make an array of them, if you were to use something like a range-based for loop
where you give it like a begin and end iterator of your array, if you use that with an array
of void, no matter how many elements there are it would execute um no times at all because the address of the end location and the address
of the zeroth location would always be equal so you'd never be able to see any iterations that
take place and you might not think this is a big deal but because you know obviously what can you
possibly do with void but you have to keep in mind mind that the body of the loop can be doing side effects.
And you can't just assume that because your elements are void, that your loop doesn't have
to run the amount of times that it should. So this is kind of like a subtle thing. And it's
really, it's like a symptom of the fact that in C++ and in C, we kind of, well, mostly in C++, we think of pointers into an array as iterators.
And in fact, we not only think of them as that, I mean, that's how we effectively define them.
And our whole iterator concepts are kind of based around this whole notion of, or they're modeled after how pointer arithmetic works.
But really what we should have done is had a different kind of iterator type for arrays from pointers.
Pointers shouldn't be able to have pointer arithmetic in general,
and it's just because already it's only really defined
if you're iterating over elements of an array anyway.
What we really should have done is we should have had a separate iterator type
for marching over the elements of an array,
and in which case if we actually had that
and it was different from our pointer type,
you'd be able to have a size of 0 type,
put it into an array,
and its associated iterator type
could just be equivalent to an integer
that counts when you increment it.
And then you wouldn't have this kind of
subtle difference between behavior
if you have an array of some non-zero size
and an array of zero size elements.
So I don't know.
Those are basically the issues.
So as I said, size is not zero.
Size, as I describe it in the proposal,
is that it's some non-zero size that's implementation dependent,
which is a common thing that we do for a lot of different types.
In practice, I expect that to mean
that the size is going to be one
and there's a really good reason to believe
that size will be one in practice
even if you didn't already consider it
like why would you want something larger than that
but GCC already allows you to
as an extension like increment
void pointers in which case it's going
by one and so that would be a change in behavior
of their extension
if all of a sudden they made size of void something different.
But that's that.
It kind of sounds like it's an overlap
with the size of an empty struct being one also.
Yeah, exactly.
I think if we were to ever solve the problem in C++
where we can't have size zero types,
it wouldn't be like void would
be the only size 0 type.
There would be some way to opt in
for your type being actually size 0.
I think that's the only way we'd be able to do it.
It would have to be like an opt-in mechanism, and it would solve it
for empty structs in addition to solving it for void.
It's out of scope of this proposal.
It's something that I wish that we
could have in the language, but I think it's not
really feasible, just based on legacy concerns. And it would be a bigger change than
what this proposal is. So I'm curious, and maybe this is going too far off into the weeds, but
if you were to have a struct that had like five void variables in it, do you imagine the compiler
doing any optimizations like it does with empty base optimizations,
like compacting those into one thing?
No, I don't expect it to happen.
I expect it to be treated by the compilers basically exactly the same way that it would
treat an empty struct, which is they can't compress them there.
So yeah, you'd have to, if you wanted to be optimal, you'd have to do what people do today already,
which is either exploit the empty base optimization.
You wouldn't be able to do that specifically for void
because you can't inherit from a fundamental type,
but you'd have to do similar kinds of tricks
if you wanted it to actually occupy zero space
in your struct that contains your void objects.
But that's not a new problem.
That's a problem that library developers already have to deal with, and it's unfortunate.
And I hope that someday we'll be able to get by that, but it's definitely out of scope of this proposal.
So you said with the first iteration of the proposal, you did get some pushback from the standards committee.
Could you tell us a little bit about what the pushback was?
Yeah. what the pushback was? Yeah, so I think part of the initial pushback was I didn't make it quite
as clear in the proposal that I as I could have that I wasn't breaking existing code. And so
I think a couple of the people who I, I spoke to in the months following, because I wanted to
really understand what the what the negative response was before I made a revision.
A lot of it was just confusion over what exactly the details were of the proposal.
And it was sort of my fault when I presented.
I was kind of expecting – it was my first standards committee meeting.
I was expecting everybody to have, like, read every paper, which is completely impossible.
And everybody would have understood, like, every paper really well,
because I had full wording in the standard for all the changes that would need to be made in the standard.
And if you were to read all of the changes, it would be very clear that basically all that I do is I eliminate parts of the standard that say things like except for void or including void. I'm basically just removing a whole bunch of special cases from the standard. And I'm not actually introducing like, uh, any new incompatibilities with things or making it. So you have to special case, but one of the claims was that, that it would require people to special
case void in their, in their code more, which is just, it was just an incorrect thing. Uh,
but there were other, there were other things that people were pushing back on that, um,
are harder to write off. And they're things that I'm
sympathetic to, even though I disagree with. One of them is that currently today, if you have a
void pointer, and you write delete of that void pointer, your compiler can can tell you, hey,
no, you can't delete, you know, void. But this today would obviously allow you to be able to
delete a void pointer pointer because it's possible
that it's actually pointing to a void object in which case that's a perfectly valid thing
so if if if you really think that the trade-off is not good where you get void being a regular type
because you think that you lose the ability to catch people accidentally deleting void pointer
i can't really argue with that i disagree disagree with it, but people weigh things differently.
I don't know.
Does that introduce an ambiguity of some sort
between a void pointer being like a generic pointer
and a void pointer being a pointer to a void thing?
It's not really an ambiguity.
I mean, you already have the ability in the language
to have pointers of different types, alias, other things.
Another example that's commonly done is like char.
Lots of times people will have char pointers
to existing objects that are of a different type.
So if you were to, for instance, dereference the
void pointer, and it didn't actually point to a void object, then that would be undefined behavior,
just as today, if you have a mismatched type, and you're pointing to an object of a different type,
and you dereference it, it's undefined behavior. Well, I think the act of dereferencing it
technically is an undefined behavior if you actually access the object.
But either way, it's not really introducing something new in that respect.
Okay.
Would regular void mean there's a change in sometimes you might have func void versus just having func with empty parameters?
Would that be different now? So you mean like if a user wrote in their function declaration
like void foo, open parentheses void?
Yeah, right.
So this is an interesting case.
So like I said, a part of this proposal,
I really do not want to break any existing code.
And in an ideal world, you would actually want
like void foo, open parentheses void
to mean
something taking a void parameter.
And that obviously conflicts with what its current meaning today is, which is a nullary
function.
So this is like one of the only special cases that I'm just completely unable to remove.
So that specific type will not change in meaning.
So if you write that out, it will not change in meaning.
However, if you actually want a function
that takes a single void parameter,
you can just give that void parameter a name.
So in other words,
instead of writing void foo,
open parentheses,
void a,
void, close parentheses,
you can write like void a
to give it a parameter name.
Then all of a sudden,
it's a unary function.
Similarly, this is only true if you're at global scope or if
you're not inside a template. If you're inside a template and the void comes from a dependent type,
for instance, if you're thinking about std promise, std promise has a member function
called set value. And it takes something dependent on the type T. So like set value and it takes something dependent on the type t so like set value you set
the value that the future is going to see and in this case if you had a future of a promise of void
the signature of this function would be um set value and it would take like a t ref or something
t reference or maybe a t ref ref uh In this case, it actually would correspond to
a unary function as opposed to a nullary function because the type is dependent.
And also because in that case, it's a reference. But if in the cases where your type is dependent,
you don't need to do anything special, you don't even have to give it a parameter name. But
that's that. That's interesting. You know, personally, I've always been it just makes
me sad when I see functions that are explicitly nullary. So I would have You know, personally, I've always been, it just makes me sad when I
see functions that are explicitly nullary. So I would have been okay if you would just change
that part of the standard. Well, we can't really do that. I mean, you can't change,
you can't change, you can't change, you know, all the code that's been written over all these years,
and you want to be somewhat compatible with C. And when I actually originally wrote the proposal,
I was talking a bunch with Richard Smith,
and he recommended maybe I should even try
deprecating the meaning of void, foo,
open parentheses, void, closed parentheses,
because he also considered it,
and other people in the committee consider it
sort of a mistake that we have the meaning
that it currently uh that it currently has yeah and so did uh when i initially presented it i had
it with like a deprecation there and there was pushback because people didn't want to actually
deprecate that meaning for the sole reason being that if we deprecated it there's basically no way
we'd ever be able to change the meaning anyway, because we're probably not going to be able to get C to change the fact that that means a nullary function. So in the revision, I removed
that deprecation. And that actually won more people over to the side of the proposal. So.
Okay. Yeah. So you have other proposals out that take advantage of template auto parameters that was added in C++17.
This is something I haven't yet played with.
So I'm kind of curious, what is an auto parameter in a template?
And how does that differ from a template type name or class parameter. So template auto. So this is a proposal that that was done by
James Tuton and Mike Spertus. And so you mentioned template type name and template class,
I'm sure you're also familiar that you can have non type template parameter kinds, such as like
template int. Yes. A common one is stood array for listeners listeners. Std array takes a class for the first parameter,
and then its second parameter is a size T of the size of the array.
So that's just a compile time constant integer that you can pass.
So what template auto is,
is it corresponds to a non-type template parameter kind that is deduced.
And specifically, it has to be a non-template.
It won't bind to template template parameters,
but it will bind to any type of other non-type template parameter kind.
So for instance, in the standard library,
we have something called std integral constant,
which takes some type as the first template parameter,
and then an instance of that type as the second one. So you might write like std integral constant, open angle bracket,
int comma five. And this represents in the type system, a constant of type int that has the value
five. But one thing that you have to do there is you have to explicitly type out int, because you
have to use it when declaring the second template parameter. What template auto does is it allows
you to instead of having something like std integral constant that takes two parameters,
you can make a std integral constant that takes exactly one auto parameter. And if you pass in
something like the value five, then it will automatically deduce the value type of that
to be int in that case.
And another example is if you write open angle bracket
and you just wrote like a single quote, a single quote, end angle bracket,
it can deduce it as a char.
So it corresponds to any value type that's a non-type template parameter kind
and deduces that for you.
So it mostly just eliminates some redundancy that people have to do
when they're
when they're doing any type of metaprogramming or things like that.
So that kind of feels like it overlaps with C++17's class template type deduction.
Um, not, not really, because what this does is this actually affects the template parameter, like not the template argument list,
but like the actual template parameter list
of the template itself.
So it can change from things that currently today
you need like two template parameters for
now become like a single template parameter.
So it actually changes the type itself,
not just how things are deduced.
So it's a little bit different from that.
Okay.
So you have then made some proposals for C++20 that take advantage of this new feature in C++17.
Is that correct?
Yeah.
Yeah.
So I think three of my proposals touch on it a little bit, but the two ones that feature it as the main thing
is that they use this feature.
One of them is we were talking about stood integral constant.
I propose having just stood constant,
which I can just verbally explain the exact definition
because it's so simple.
It's template template open angle bracket
auto close angle bracket um using constant equals stood integral constant and then decal type of
the parameter comma the parameter value so it basically is just an alias of stood integral
constant that um that automatically deduces the value type for you uh okay. So that's, that's just a very simple one liner proposal. I only, I presented it
once to a small subgroup, a subgroup of LEWG, just to get some feedback. And I plan to come back with
it and actually formally propose it. And then the more interesting proposal that I have that uses it is what I call monostate function. And what
monostate function is, is it's a type or it's a template that takes a single, a single auto
template argument. And what you normally try to pass to it is the is a function pointer type.
For me, let me think if I could explain this a little bit a little bit
better it's hard to explain it verbally without code let's say you have let's say you have a
stood set and you want to override the comparator for your stood set and specifically the type of
the the type of your comparator that you want to pass uh corresponds to something that you want to pass corresponds to something that you already have as a function. So not as
like a function object, but just a function. And you want to just specify, hey, I want to use this
function here as the comparator. What you'd have to do today, or one of the ways you can do this
today is you can specify a function pointer type as your comparator kind. And then in the constructor of your set,
you can initialize your comparator by passing in an instance of the of the pointer that corresponds
to the function that you want to call. But this is kind of horrible, because it's it,
it requires the user to be redundant, they have to specify a function pointer type manually.
If they forget to initialize the comparator when they create an
instance of their set, then they have undefined behavior if they go and try to actually insert
things into their set. Another example of this is, let's say you want to have a deleter for your
unique pointer, and you have some kind of deletion function that already exists. And again, it's just
like a function pointer. You want to be able to somehow specify that specific function as a deleter and currently today you'd have to put
like a function pointer type as the deleter and then pass into the leader manually what monostate
function which is the thing i'm proposing uh does is it just takes it's a temple that takes a single
a single auto parameter and you give it something like a function pointer type, and it turns that
function pointer into a function object that occupies no space, but that when you default
construct it, it's fully formed, and it has an overloaded function call operator that will just
call your original function that you passed it. So it allows you to do things like create deleters
for unique pointers, or create comparators
for things like sets, and have them work with a function pointer. And you just do it right at the
place where you create, or where you name the type of your set, or you name the type of unique
pointer without having to add any other type of initialization through the unique pointer
or sets constructor. I don't know how clear that was, but... I think it makes sense. It's like your constant proposal, and in this case,
the constant is the function pointer, and you add a call operator.
Right, exactly. So where a std integral constant takes some compile time constant value and exposes
a colon colon value, what this does is it takes a compile time constant function pointer, and it exposes a function call operator. And in either case, the std integral
constant, you know, is an empty type, and the monostate function is an empty type. But they
give you a way to kind of pass the information about what the value is that you're representing
in this stateless type. So you don't need to initialize it, you don't need to do anything
else at runtime. It's interesting, I was for a parser that I'm working on, I did something
similarly, but obviously not using the C++17 features for, um, string constants that gave
you some, you know, begin and kind of functionality on a string constant. Yeah, that's cool. It seems
to be like a recurring kind of theme where we have these runtime values
and you want to be able to pass them around
and have their value be a part of the type system.
So something a little bit even more compile time constant
than constexpr,
something that's actually tied to the type of the variable
that you're passing around.
I think auto makes it easier to do some of these things.
So it'll be interesting to see how this feature plays out
in future standards, what kinds of uses people come up with.
I have to play with that.
I wanted to interrupt this discussion for just a moment
to bring you a word from our sponsors.
Backtrace is a debugging platform that improves software quality,
reliability,
and support by bringing deep introspection and automation throughout the software error life cycle. Spend less time debugging and reduce your mean time to resolution by using the first and
only platform to combine symbolic debugging, error aggregation, and state analysis. At the time of
error, Backtrace jumps into action, capturing detailed dumps of application and environmental
state. Backtrace then performs automated analysis on process memory and executable code to classify
errors and highlight important signals such as heap corruption, malware, and much more.
This data is aggregated and archived in a centralized object store, providing your team
a single system to investigate errors across your environments. Join industry leaders like Fastly,
Message Systems, and AppNexus that use
Backtrace to modernize their debugging infrastructure.
It's free to try,
minutes to set up, fully featured with
no commitment necessary. Check them out
at backtrace.io
slash cppcast.
Do you want to talk about concepts for a bit?
You mentioned in your bio that
you think you might be responsible for concepts
not making it into C++17.
I don't think, I don't think, no, I actually, I don't think I'm responsible.
I, I, I, I wouldn't be surprised if I contributed to some of that.
And that's not something that like, I'm, it's not something I would say I'm proud of.
And it's not something that I would say that I'm, that I'm not proud of.
I basically just expressed my opinion that I did not think that, that they were ready.
Uh,
but a lot of people apparently shared that opinion, uh,
as,
as is obviously the case because didn't actually end up getting into a C plus
17.
Um,
so what is your argument?
Why do you think it was not ready yet?
So my,
the reason why I say that I don't think I influenced much,
uh,
much of the standard committees,
uh,
decision there is because my concerns are
actually very different from what uh what a lot of other people had for concerns okay uh so what a
lot of other people's can i'll talk about what other people had uh issues with for concepts but
before my own but uh some of the some of the problems with concepts were that we didn't in
conjunction with the actual feature have a standard library that was making use of concepts.
So we didn't really have a proof of concept yet.
We have ranges.
Ranges is probably the best use case for concepts that they've been using it for quite a while,
and they don't seem to have very many problems with it.
But we don't have anything actually in the standard. so that was something that bothered some people a little bit bothers
me a little bit but um that's not my my biggest issue another thing was the the the language
feature introduces some new ambiguities that were unresolved uh it has some really strange
syntactical elements that did not exist prior to concepts being in the language.
It introduces a way to declare templates without actually writing template.
We already have this with generic lambdas, but it introduces it for global functions and things like that, you're able to write like a function, open parentheses,
and then a concept for the parameter name and then followed by the actual,
the end declaration.
That will implicitly become like a template
that's constrained by that.
A lot of people didn't like that.
My personal problems,
like all of that aside,
my personal problems were a much more fundamental thing,
which is that this proposal,
in my opinion, does not have any way of us getting to a place where we will be able to
do concept checking of the definitions of functions prior to them being instantiated.
If I could elaborate on that a little bit, right now what this concept proposal does is it's sort of a replacement for what we currently do with things like std enable if.
So you have a template and you constrain it by some requirements like the specific overload of your function is just ignored when substitution takes place.
But the other aspect of concepts, in my opinion, that's very important is, let's say you constrain your function by, for instance, copyability. So in other words, you require that, well, we'll say movability,
you require that the type, an instance of the type that you pass to this is a movable type,
but you don't necessarily state that it's a copyable type. Inside the function definition,
if you do something like copy your object, it would be nice if you'd be able to get like
a compile time error for this, because you never stated in your in your requirements list that
your type was able to be copied uh and i do not see for sophisticated cases how this current
proposal will be able to move us in that direction for allowing that and the reason why it bothers me
so much is we had a the c++ 11 proposal for concepts was very different and very integral to its whole
uh definition of concepts was the the ability to do concept checking of definitions of functions
and things like that and the way they did it was they actually had to change like the meaning of
of what it was to be inside the definition of a constrained function it had to alter things like
how name lookup and overload resolution took place from within the body of a constrained function. It had to alter things like how name lookup
and overload resolution took place
from within the body of the function,
which I think are completely important
to doing concepts correctly.
A lot of people disagree with me on this.
This is one of the reasons why concepts
didn't make it into C++11,
was that people thought that it was a little bit too restrictive.
It's hard to go over the details verbally on the air,
but there were definitely,
there's a post that was made by Faisal Vali a few months ago
asking about my paper in the SGA forums.
And we go into, he was just asking, like, are my concerns warranted?
And that ended up spawning, like, a big discussion.
And I give a bunch of examples of the issues in that thread,
if anybody is really curious.
But anyway, those are my specific problems with concepts today.
But it's surprising that
there are a lot of reasons why concepts
got cut, and this is just one very, very minor
one.
Do you
feel confident that's going to make it into C++
20? Like some of these changes
that you're worried about will be made?
I don't know. I think
not everybody agrees that there's no
path forward for function definition checking. I am pretty much convinced that there is no path forward for it. And one of the main people behind the previous iteration of concepts also shares in that opinion that it seems like there's not going to be any path forward for adding it in the future. However, the people behind concepts, a lot of them feel that there
is a path forward. Although I'm hesitant, because while I personally don't see it,
they also don't have a proof of concept of this in C++ that actually does it. And I,
it's something that I'm not willing to take on faith right now, what this concepts does is it
adds a whole bunch of new syntax to the language. And in my personal opinion, while it's, it's cool because it's able to get rid of things
like, uh, the requirement of things like std enable.
If I'm, I'm worried that it's not enough of an improvement to warrant this type of,
you know, vast change to the language.
And if we're going to make this type of change, I want it to be done right.
And I'm just really worried that we're going in the wrong direction.
So my impression is that the older concepts proposal was an even more vast change to the
language. And this proposal was accepted, or at least moved forward, because it was a smaller change. We added some syntax, and then, you know, it made people happy in some sense. with like an entirely new syntax and scrapping behavior is we could have just scaled back
the previous iteration of concepts and doug gregor who's one of the main people behind the previous
iteration um wrote a paper on this a few years ago unfortunately it was mostly ignored because
we were already moving forward with concepts light which is just we could have just scaled back
all the effort that we did in the previous uh, eliminated a lot of the things that people consider too complex, eliminated a lot of the controversial stuff.
But unfortunately, that did not go over that well.
And a lot of the people who are behind the previous iteration of concepts are no longer active in the community. Like Doug, for instance, is now
he's at Apple, and he works on the Swift programming language, which is an absolutely
fantastic programming language. And I sort of wish that he had not left the C++ community. But
that's that's kind of the state that we're in. So in my opinion, part of part of the reason why
we're moving forward with this iteration of concepts is just we don't have anybody really championing um what i personally consider to be better concepts um and that's kind of
why we're here but okay okay but that said there's like i i actually do like this iteration of like
for all the negative things that i say i actually do like this iteration of concepts i like all the
work that andrew is doing i'm just worried that i really just being truthful i don't see it being um
having a path forward for for being the type of language feature that we want it to be or that a
lot of people expect it to be which is something that will be able to you know check the definitions
of your functions at the time you write your function templates prior to them being instantiated. Makes sense. As a standards committee member, are there any features that didn't make it
into C++17 that you think should have? I really wish that we had some form of default comparisons. I do agree that there were problems
with what we currently had in the proposal
that was moving forward.
And it's unfortunate that we couldn't make it work.
I think that having something akin to default comparisons
is really important to the language.
It makes code so much easier to write.
And it makes working with makes code so much easier to write. And it makes working with like
generic algorithms so much easier, because if you don't have to manually write things like
comparison operators yourself, you know, on your own, and the default actually works, people are
going to be using things like standard algorithms much more frequently, because, you know, it doesn't
require them doing more boilerplate. Yeah, I can totally see that.
Yeah.
But yeah, so if anything, I would say, yeah, default comparisons.
I wish we had something like that in 17.
But I'm also really confident we will have something like that in C++ 20.
So if people can hold off a little bit, we'll get there.
I never read the proposal for that,
but I kind of assume operator know operator equals equals operator less than and then we would have like you could
do equals default equals delete if you wanted to just like other default operations so part of part
of the problem with with this proposal or part of one thing that a lot of people had that a lot of
people took issue with was that it wasn't um it wasn't opt-in it was opt-out
right so in other words uh it's not like if you didn't let's say you have an existing type uh
it automatically will have a an equality operator after this change assuming it meets all the other
requirements uh as opposed to you having to opt in and say equals default. And so this
actually changes, it has the ability to change existing types, which is is a little bit scary.
And it can even change the meaning of existing code, which is also kind of scary. So a lot of
people really did not like that. I will say that this is one of those things where like, if we were designing SQL plus
from from scratch, I think everybody would want, you know, operator equals equals to
be defined by default, and you wouldn't have to opt in for it.
But a lot of the hesitation comes from the fact that, you know, we're not starting from
scratch, we have the language as it as it is today.
And we have to be very careful to not change the meaning of programs
in very subtle ways from standard to standard. And it's kind of an unfortunate thing. But it's
a valid concern. Right? Maybe to finish off, you're also on the program committee for C++ Now. Do you
know if there's going to be a call for speakers soon or any other news you might want to share so yeah uh so it's people
supposed now 2017 it's the week of may 15th may 15th to may 20th uh we do we have not yet put out
a uh a uh call for papers call for proposals for talks but uh we expect to do that either by the
end of this year so very soon or the beginning of next year. So it should be coming very soon. We also haven't announced keynote speakers yet, but we have some great stuff planned.
Awesome.
And for people who aren't familiar with C++ Now, it's a small conference in Aspen. It originally
started off as BoostCon back in, I think, 2006. This is the 11th year it changed the name to c++ now i think four or
five years ago and uh it's a much smaller conference than uh than cpp con i i think it's
it's a much more interesting con uh conference in that i think that there's a much higher
percentage of people who are attending who are like members of the standards committee or boost library authors and things like that and uh it's you really get a chance to to talk to people at the conference who are on
the standards committee and if you're like ever if you're ever curious about why things in the
language are a certain way and uh if if you just happen to be in the lounge like in the in the
middle of the conference you can just talk to anybody you want. Like, like Sean parent is frequently there. Not that I'm not that I'm advertising that Sean parent,
you know, like it's, it's just really, it's a really fantastic conference and I can't, I can't
say anything but the best about it. And I'm not just saying that as somebody who's on like the,
the, the program committee for it. It's just, it really is just an amazing, amazing conference.
It's a great venue also.
Yeah, Aspen is absolutely awesome.
I've been encouraging the members of my C++ users group
that they want to go also,
because it's an easy drive from Denver.
Okay, well, Matt, where can people find you online?
Do you have a blog or Twitter or anything?
My Twitter is cppsage. I don't have a blog or anything. anything? My Twitter is CPP Sage.
I don't have a blog or anything.
Maybe I should make a blog.
Okay.
Well, thank you so much for your time today.
Thank you for having me.
Thanks for joining us.
Thanks so much for listening in as we chat about C++.
I'd love to hear what you think of the podcast.
Please let me know if we're discussing the stuff you're interested in.
Or if you have a suggestion for a topic, I'd love to hear about that too. You can email all your
thoughts to feedback at cppcast.com. I'd also appreciate if you like CppCast on Facebook and
follow CppCast on Twitter. You can also follow me at Rob W. Irving and Jason at Leftkiss on Twitter.
And of course, you can find all that info and the show notes on the podcast website