- Hi!
My name is Timur.
So you've already I think all been there.
Someone shows you this
really weird snippet
of really weird C++ code, and tells you
did you know this is valid C++?
And you're like what?
And you're like oh okay.
But no one is going to
write code like that anyway.
Then you go off and have a nice day.
But you can't do that if you maintain
a C++ parser.
If you do that then you have to like
oh okay, sit down with
the standard and figure
out where if it's actually valid code.
And if it is, and it
doesn't work, fix the bug.
So what you end up doing a lot
is staring at the C++ grammar.
C++ has a grammar.
It's what, 20 pages in the
standard that looks like this.
There's beautiful things in there like
pseudo-destructor-name,
elaborated-type-specifier,
or the nodecispec-function-declaration.
Which of course a
function declaration with
no decla-specifier sect.
But actually, you know this grammar
is a just an aid to comprehension.
It's not an exact
statement of the language.
And in particular, all these
really complicated rules
must be used to weed
out syntactically valid
but meaningless constructs.
But it turns out even if you do all that,
then there's still a lot of weed growing.
For example, linkage-specifiers.
This kind of extern C kind of thing.
Grammar for that is well,
linkage-specification
is the declaration and it can also contain
the declaration with
braces, without braces
so it actually nests right?
So it can nest with braces,
it can also nest without braces.
(audience laughs)
And actually extern has a second meaning.
Extern can actually be
a star specifier right?
Which is also part of the declaration.
So you can put it...
well, where do you put it?
(audience laughs)
In the beginning or in the end?
Well, which one is correct?
(audience member interjects)
(audience laughs)
God mode is not going to help you
because Microsoft rejects the first,
GCC rejects the second,
and (mumbles) thinks both are okay.
(audience laughs)
Great C++ 17 feature, if with initializer.
The initializer is the
thing before the semi-colon
it's great to initialize a variable.
Here's the grammar for it.
It turns out in the statement,
that's the thing we're talking about here.
Can be either a declaration
or an expression
basically it means it can
be pretty much anything.
So you can forward declare
a class in there, that's valid.
(audience laughs)
You can put an expression
in there like false,
that's valid C++.
(audience laughs)
You can put an empty
expression in there as well,
that's also perfectly valid C++ grammar.
I find a lot of compiler bugs when
I was looking at these things.
Great topic, initialization.
You already saw a talk
on initialization this week.
There's about 50 ways you
can initialize an int,
these are just four of them.
The best one of course is
the one with parenthesis
because it's so great that parenthesis,
you know they appear
everywhere and they conflict
with everything so that's
definitely my favorite one.
Let's take for example,
take function pointer
which also has a lot of parenthesis.
This is of course not more on C++,
we have to write a
trailing with giant type
that's much better.
And because a function
pointer is variable,
you can initialize it.
You can put the initializer in parenths.
That's great.
(audience laughs)
Most parsers will just say no.
But, you know, it's valid.
You can also put parenths
around decelerators,
like variable names, right?
Which is great because ...
for example you have a function that takes
a foo which is a struct.
Let's give this parameter a name,
let's also call it foo
just because we can.
(audience laughs)
Let's put parenths around the declarator.
Now we all know this is the vexing parse.
Now it's different thing right?
It's actually a function,
taking a function,
taking a foo, turning a foo, turning void.
Great, that's the vexing parse.
But, actually this is not
the most vexing parse.
There's some more vexing parse.
Which happens if you put
another pair of parenthesis
around the thing.
So what type is this?
(audience laughs)
Anyone knows?
(audience member interjects)
So different compilers again
use very different answers.
(audience laughs)
Right, next thing
elaborated-type-specifier.
That's really great.
So it's used here if you have like bar,
and it's an int, and it's also a class.
And you know you can't
declare a bar like that,
you have to kind of disambiguate it.
But it turns out that
actually you can just
use it like, you know, it's optional.
But you can just use it.
It actually turns out
the grammar says you can
use it everywhere, you can
use a normal-type-specifier
so if you have something like this.
You can sprinkle the whole thing
with elaborated-type-specifiers.
(audience laughs)
It's great.
You can actually automate this,
you can write a script that adds in there
whichever type specifier everywhere where
grammatically it's valid.
It's great because every
parser will just blow up.
It's fun.
They're also great because they're also...
Elaborated-type-specifier
also can simultaneously
act as a forward declaration.
Right?
So this takes a pointer to S and also
automatically forward declares S.
So that is actually
gonna compile even if S
is not declared anywhere.
(audience laughs)
And actually it's great because it has
really weird scoping rules.
Like if you put that in a class it
is still gonna be visible outside.
(audience laughs)
Yeah.
Great feature I love C++.
Pseudo-destructor-name that is another one
which is really great.
So pseudo-destructor-name is still there
with type-name so it
looks like a destructor.
But actually, the actual destructor
would be still the class-name.
Class-name and type-name
are different things.
So a type-name would be a type
which is not a class, in this case.
So you can do something like this
except actually you can't because int
is actually not a type-name,
it is a type specifier.
So you have to use, using,
and then it's okay.
(audience laughs loudly)
(audience claps)
But feat not, fear not.
So the destructor for int doesn't work.
Let's declare one.
That compiles!
(audience laughs)
Unfortunately, this is of course not
a destructor this is a default
constructor is int which is zero and then
bit not right?
(audience laughs)
So still the thing is
really ambiguous right?
It's like it could be one or the other,
so I have a suggestion
how to make it better.
So that never confuse destructors with
these kind of things.
So if you have a class and you declare
a constructor and destructor
and there's still the thing.
And really want to make
sure that's not the
bit not till there.
You can actually write it like that.
(audience laughs)
Because we have alternative tokens!
Right?
So the alternative token for till there,
is compl, which is great.
So now this doesn't look
an expression anymore.
So, it's nice and clean.
And actually this doesn't
work only for destructors,
it also works for copy
constructors and move constructors,
you can also use alternative
tokens for those.
(audience laughs)
This is also valid C++.
So, I recommend we declare our special
mema functions like this,
because it looks much cleaner,
You know it's much simpler to English.
(audience laughs)
Much more like English you know?
We want our code to look like English.
Not like gibberish right?
So yeah, great that's
all I have thank you.
(audience applause)
