We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback
00:00

Formale Metadaten

Titel
C++14
Serientitel
Anzahl der Teile
170
Autor
Lizenz
CC-Namensnennung - keine kommerzielle Nutzung - Weitergabe unter gleichen Bedingungen 3.0 Unported:
Sie dürfen das Werk bzw. den Inhalt zu jedem legalen und nicht-kommerziellen Zweck nutzen, verändern und in unveränderter oder veränderter Form vervielfältigen, verbreiten und öffentlich zugänglich machen, sofern Sie den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen und das Werk bzw. diesen Inhalt auch in veränderter Form nur unter den Bedingungen dieser Lizenz weitergeben
Identifikatoren
Herausgeber
Erscheinungsjahr
Sprache

Inhaltliche Metadaten

Fachgebiet
Genre
Abstract
Is the next minor update to C++ after C++11. It was finished in February 2014 and provides several small improvements and fixes for both the language and the standard library. This talk gives an overview of what is new in C++14 and about the most important fixes to C++11 provided with C++14.
3
Vorschaubild
59:06
71
112
127
130
TelekommunikationFundamentalsatz der AlgebraProgrammbibliothekZeitabhängigkeitModul <Datentyp>RechnernetzGleitkommarechnungSoftwaretestGruppenoperationBeobachtungsstudieDatenbankFormale SpracheE-MailDatenparallelitätSpeicherabzugWeb SiteKonvexe HülleElement <Gruppentheorie>Wechselseitige InformationHypermediaAbstimmung <Frequenz>MathematikVollständiger VerbandWeb SiteDifferenteVersionsverwaltungProgrammbibliothekComputerarchitekturMultiplikationTypentheorieMAPFormale SpracheProzess <Informatik>SchlüsselverwaltungProgrammierungEinfügungsdämpfungMultiplikationsoperatorCodecWeg <Topologie>Wort <Informatik>CD-ROMZeiger <Informatik>SoftwaretestSystemaufrufGruppenoperationElement <Gruppentheorie>NeunzehnRichtungEvoluteGrenzschichtablösungGlobale OptimierungImpulsMaßerweiterungIterationResultantePunktData MiningObjekt <Kategorie>StabCASE <Informatik>HochdruckNichtlinearer OperatorFormale SemantikEinsPhysikalisches SystemService providerDienst <Informatik>ProgrammfehlerStandardabweichungAppletVollständigkeitElektronische PublikationDateiverwaltungComputeranimation
SpieltheorieWechselseitige InformationElement <Gruppentheorie>ZufallszahlenTelekommunikationDialektData DictionarySpezialrechnerZahlzeichenBinärdatenGleitkommarechnungZeichenketteDefaultSichtenkonzeptKlasse <Mathematik>Nichtlinearer OperatorTypentheorieMaskierung <Informatik>ResultanteStreaming <Kommunikationstechnik>Folge <Mathematik>Element <Gruppentheorie>LoopDelisches ProblemDomänenspezifische ProgrammierspracheKardinalzahlFormale SemantikBinärcodeZeichenketteDigitalisierungGrenzschichtablösungZeitrichtungCASE <Informatik>RichtungWeb SiteComputerspielEin-AusgabeKartesische KoordinatenNichtlinearer OperatorInterface <Schaltung>MaßerweiterungZeiger <Informatik>IterationMultiplikationsoperatorSchreiben <Datenverarbeitung>ZweiSoundverarbeitungZahlenbereichGeradeTypentheorieLesen <Datenverarbeitung>Funktion <Mathematik>AnfangswertproblemKomplexe EbeneQuellcodeSpannweite <Stochastik>Einfacher RingSoftwaretestAbgeschlossene MengeGefangenendilemmaProgrammierungTouchscreenKomplex <Algebra>Quelle <Physik>SystemaufrufUmwandlungsenthalpieStandardabweichungPunktBitrateVierzigComputeranimation
Minkowski-MetrikFehlermeldungTelekommunikationZeichenketteROM <Informatik>TypentheorieUmwandlungsenthalpieNichtlinearer OperatorKlasse <Mathematik>StandardabweichungTemplateVariableDefaultParametersystemOverloading <Informatik>StatechartE-MailLoopBildschirmsymbolElement <Gruppentheorie>ZeitabhängigkeitMenütechnikKonditionszahlObjekt <Kategorie>Prädikat <Logik>TemplateEinsSpeicherabzugCodeProgrammierungVariableFunktionalUmsetzung <Informatik>Arithmetisches MittelProgrammiergerätKlasse <Mathematik>MinimumDefaultTypentheorieKonstanteSchnelltasteThreadZweiProzess <Informatik>ZählenSchlussregelSystemaufrufImaginäre ZahlDämpfungAlgorithmusImplementierungElement <Gruppentheorie>LoopVektorraumStandardabweichungWort <Informatik>Rechter WinkelTermDelisches ProblemService providerStatechartMinkowski-MetrikNichtlinearer OperatorParametersystemGüte der AnpassungMathematikGeradeFehlermeldungTaskBitRechenschieberFormale SpracheZeichenketteProgrammbibliothekKardinalzahlKomplexe EbeneSchnittmengeEreignishorizontPi <Zahl>Nabel <Mathematik>VererbungshierarchieInstantiierungPuls <Technik>ZeitrichtungDatensatzQuelle <Physik>EinflussgrößeMereologieRationale ZahlRichtungARM <Computerarchitektur>UmwandlungsenthalpieBitrateComputerschachSoftwaretestComputeranimation
BildschirmsymbolLoopElement <Gruppentheorie>ZeitabhängigkeitTelekommunikationNichtlinearer OperatorFunktorLambda-KalkülVektorraumInklusion <Mathematik>CAN-BusSCI <Informatik>Motion CapturingMinkowski-MetrikAlgorithmusFunktionalVariableQuick-SortThreadZeiger <Informatik>ZahlenbereichProgrammierungDefaultRegulärer AusdruckMinkowski-MetrikDifferenteZeichenketteElement <Gruppentheorie>VektorraumTemplateFunktionalMathematische LogikBoolesche AlgebraProdukt <Mathematik>RechenschieberGüte der AnpassungWeb SiteBildschirmmaskeSchnelltasteDomänenspezifische ProgrammierspracheNichtlinearer OperatorKonditionszahlMusterspracheKlasse <Mathematik>Motion CapturingLambda-KalkülAbgeschlossene MengeVariableIterationSpeicherabzugGamecontrollerFormale SemantikProgrammiergerätTypentheorieWinkelPoisson-KlammerExtreme programmingFormale SpracheInnerer PunktInstantiierungProgrammbibliothekParametersystemAlgorithmusMathematikGleichheitszeichenFehlermeldungEindeutigkeitEinfügungsdämpfungARM <Computerarchitektur>MinimumMAPGeradeBitUniversal product codeStandardabweichungSichtenkonzeptZweiSchnittmengeRichtungMatchingMultiplikationsoperatorSoundverarbeitungMetropolitan area networkComputeranimation
Lambda-KalkülFormale SpracheVariableMotion CapturingTelekommunikationObjekt <Kategorie>Funktion <Mathematik>Zeiger <Informatik>EindeutigkeitTemplateSchlussregelDefaultKonstruktor <Informatik>GenerizitätSpannweite <Stochastik>QuellcodeElement <Gruppentheorie>Transformation <Mathematik>Befehl <Informatik>Innerer PunktHook <Programmierung>CAN-BusHochdruckParametersystemTypentheorieParametersystemProgrammbibliothekLeistung <Physik>Formale SpracheGanze ZahlSystemaufrufTypentheorieLambda-KalkülNichtlinearer OperatorProgrammierspracheTemplateFunktionalMaßerweiterungSchlussregelBefehl <Informatik>Deklarative ProgrammierspracheBitMereologieMusterspracheCompilerMotion CapturingSampler <Musikinstrument>Web logSpeicherabzugWort <Informatik>Formale SemantikObjekt <Kategorie>StandardabweichungRechenschieberKlasse <Mathematik>DefaultKonstruktor <Informatik>Bus <Informatik>Message-PassingInformationsspeicherungMultiplikationGenerizitätRechter WinkelProzess <Informatik>MultiplikationsoperatorKartesische Koordinatenp-BlockArithmetisches MittelMultifunktionBenutzerbeteiligungComputerspielSchlüsselverwaltungPhysikalischer EffektFrequenzComputeranimation
Funktion <Mathematik>TelekommunikationParametersystemTypentheoriePrimzahlzwillingeZeichenketteFehlermeldungStellenringKonstruktor <Informatik>Auflösung <Mathematik>Mailing-ListeInformationsüberlastungElektronischer DatenaustauschSystemaufrufDefaultNichtlinearer OperatorUmsetzung <Informatik>OvalFormale SemantikInformationsüberlastungSchlussregelVektorraumAuflösung <Mathematik>Formale SpracheUmsetzung <Informatik>TypentheorieElement <Gruppentheorie>ParametersystemGüte der AnpassungAnfangswertproblemInnerer PunktGleichheitszeichenFunktionalFehlermeldungMailing-ListeProgrammfehlerDifferenteBefehl <Informatik>Objekt <Kategorie>MultiplikationsoperatorZeichenketteSystemaufrufKonstruktor <Informatik>SpeicherabzugZweiResultanteBildschirmmaskeDefaultRechter WinkelExpertensystemDifferenzkernGruppenoperationRichtungStellenringComputerspielBus <Informatik>WhiteboardFormale SemantikMinimumProgrammbibliothekTechnische OptikBasis <Mathematik>VererbungshierarchieVorzeichen <Mathematik>eCosComputeranimation
Mailing-ListeTelekommunikationSystemaufrufFehlermeldungDefaultKonstruktor <Informatik>ProgrammbibliothekVektorraumOvalBetriebsmittelverwaltungEin-AusgabeKommutativgesetzFarbverwaltungssystemAuflösung <Mathematik>PermutationSpannweite <Stochastik>AlgorithmusSchnelltasteAttributierte GrammatikFunktion <Mathematik>Klasse <Mathematik>Formale SpracheTypentheorieROM <Informatik>Konstruktor <Informatik>DefaultKlasse <Mathematik>ZweiVektorraumSoundverarbeitungDifferenteMathematikProgrammbibliothekGüte der AnpassungParametersystemAusnahmebehandlungGleichheitszeichenMailing-ListeInformationsüberlastungGenerizitätAlgorithmusPermutationPaarvergleichSpannweite <Stochastik>Folge <Mathematik>Ganze ZahlStandardabweichungElement <Gruppentheorie>Umsetzung <Informatik>ZahlenbereichWurzel <Mathematik>BetriebsmittelverwaltungProgrammfehlerMinimumDeklarative ProgrammierspracheMusterspracheCASE <Informatik>Regulärer AusdruckBitCompilerAttributierte GrammatikGewicht <Ausgleichsrechnung>Message-PassingFormale SpracheInterface <Schaltung>TypentheorieComputerspielExpertensystemURLSoftwaretestVorzeichen <Mathematik>TemplateDifferenzkernSystemaufrufExploitWärmeausdehnungSchlussregelArithmetisches MittelGruppenoperationLie-GruppeMultiplikationsoperatorSchnittmengeBus <Informatik>Nabel <Mathematik>COMNichtlinearer OperatorKonstanteStabComputeranimation
Computeranimation
Transkript: Englisch(automatisch erzeugt)
So, I think we can start. Hi everybody. I don't see anything. You have to scream so that I know that you're there. C++ is back. A lot of people are sitting here and you're probably not Java programmers, aren't you?
You are, maybe. So, welcome to the C++ track here at NDC. By invitation, three guys were invited to give two talks about C++ each. Andrei Alexandrescu, Scott Myers and me. And let me say something first.
Nobody of us three understands C++ completely. So, we still fight and discuss. For example, yesterday evening we had a dinner and we discussed one hour about the details of return value optimization. So, it might happen that we ask our questions ourselves during this day.
Let me ask you one question, though. Who's familiar with C++11? Okay, a majority, but not everybody. So, although this talk is about C++14,
I will from time to time say something about C++11. So, just about me, you hopefully know all my books and bought them and will buy them again in the future. I also have a service oriented architecture background and I'm self-employed, so there's no company.
Just, you'll see, there's two self-employed people. That's it for advertisement. So, this is the topic. We have C++ standards. We started with the first standard in 1998. And then we had a bug fix called C++03.
And then there was a big, big gap of years. It was planned that this gap is only five years, but it turned out to be longer, so that finally in C++ in 2011 we finished the next major standard. And this is not the end, but it seems we are going in the right direction because we created a lot of momentum, it seems.
So, for example, at the meetings where we standardized C++, a lot more people come now to these meetings, so the group has grown from about 50 to about 100 people for each meeting. And by the way, the next one is in two weeks in Rapperswil in Switzerland,
so if you want to join, join, join. So, we are now talking about C++14, and C++14 is a minor new release with some fixes and very little extensions to the library. The next big thing will be C++17.
And C++17 will probably contain a lot of results of a couple of working groups we have right now. Here you see how we organize our work. It's a huge amount of work, and we have different working groups to deal with that. And, as you can see, we have 13 different working groups.
For example, file system, concurrency, which are probably the most important ones, but also the others. Not every group will provide something for C++17, but, for example, the file system, there will be probably a file system standard in C++17.
And then we have the general groups discussing about library or the evolution of the library, and the core, the language, and the evolution of the language, and then we have the formal full committee. And, as I said, you are all invited to join our meetings.
It's open. It's an open standardization agenda. We meet two or three times a year, and formally you are not allowed to vote in every meeting, but, informally, everybody is welcome and can even vote informally when we discuss about features in detail.
So, just in case you complain about C++, it's all your fault because you wasn't there. Because you have to understand there's nobody paying us a million bucks per year to have a good standard. It's just that whoever wants to propose something proposes something, proposes a change, and then we all discuss it,
and then we all agree. So, if there's something missing, it's your fault. Please come to the meeting, propose what's missing. If there's a bug, come to the meeting or propose a bug fix and explain why it should be fixed. So, yeah, we are open, but, of course,
we have a lot of things to discuss, so it's often better to come and join. And, as I said, you're welcome. So, we talk about C++14, and C++14 is just voted. It's just done. It was done at the beginning of this year, two months ago,
in the last standardization meeting. However, it's already supported at some compilers, so GNU has support for it, Clang has support for it, and even Microsoft has partial support of it. So, for example, here you see,
if you want to try out some features of C++14, just use the latest 4.9 version of GCC and compile it with minus std equals C++14. And there are websites where you can see which feature is implemented in which version of GCC.
So, just to catch you up, before we go into details of C++14, let's look into C++11, and this is my one slider to explain the difference between C++03, the old C++, and the new modern C++11.
On the left side, we create a multimap. As we need the type of the multimap several times, we make a type definition, and then we want to insert a couple of elements in this multimap. So, multimap is a key value container.
And unfortunately, it's not as easy as it should be. We have to say, let's insert an element which is a pair of here an English word and a German word. So, this is a dictionary, in fact. And then let's print all the elements. And here you see a lot of ugliness,
not the essence you want to program. You just see, yeah, how it is in C++. And there are good reasons why it has been that way in C++. One important thing is to print all the elements, we needed iterators, and I couldn't explain C++11 without explaining iterators,
or couldn't explain containers without explaining iterators. I had to use a pointer-like object, like an iterator. I needed pointer-like semantics like star or the arrow operator, and that was all very nasty in case you don't need it. That has changed, at least partially.
So we go at first in C++11 in a direction where we make the life of the application, of the ordinary application programmer, more easier. So here on the right side, now we just, for example, can insert all the elements.
We can even initialize, we could even initialize the container with all the elements just using brace initialization. So you just write what you want to insert, and that's it. And to iterate over all elements, you can use a so-called for-each loop
where you can say, okay, here, let's use for-each element in this dictionary, let's do something. And we don't have a pointer here, we just call the member first of this element instead of dereferencing an iterator with a pointer-like interface.
So that's it. It's still nasty to some extent. For example, you have to write const auto reference here to get a better performance, which means no unnecessary copy for each element. But we are working on that.
So this will probably be a fix in C++17. We will probably introduce a new range-based for loop where you don't declare the element to have any type so that you then iterate over all the elements without unnecessary copies.
But that's future. That's C++17. Now we talk about C++14. And there is another major path C++11 went, which is better performance. You don't see it in this program, but in principle, a lot of examples show
that C++11 is or can now be a lot faster. I will talk about that in my second talk today about move semantics and pushback and noexcept. Okay. So that's just for the beginning. So let's go through what we have.
I start with some small extensions we have in C++14, and then I come to one major extension, and then let's see how much time we have. So here are some small things. First thing is you can now define binary little,
binary numeric little just by leading 0B. So here autoA is a value of 42. And you can use a digit separator to write numbers so that you are able to read your own source code. So just the hyphen there is just to separate the digits.
It doesn't have any effect on the value or its type. So it's absolutely the same than assigning or initializing or comparing with one million here. And of course you can do both together. So here we assign B with the value of the byte 8
and the hexadecimal byte F expressed in binary form, for example. So next thing we have, we have a new manipulator. So it's now possible, and if you know Boost, you might have seen that already.
It's now possible to write strings to any device and read in the strings again and you get the same value. The problem is that there are special characters which you have to escape. And the interface quoted or the manipulator quoted
allows to do that for you. You see it here if you have a string S and it is initialized with a string literal which contains the special letters like ampersand or quotes
or the backslash. You can, by the way, I could instead initialize this S as a raw string with the syntax on the second line. So everything in red is the value of the string.
And if I now wrote this quoted, with a quoted manipulator to an output stream, I get what more or less was the initialization line at the beginning of when I declared S. So which means each double quote is escaped by an escape site
by a backslash, each backslash is also escaped by a backslash. And now if I read in this string, this value from an input stream having exactly this sequence of characters, I will have my original value again. So you don't have to deal with the semantics of quoting, etc.
And by the way, you can choose your own delimiters, so what starts and ends the string, and your own escape character. You see here at the bottom another example where I wrote out the string above
with the single quote for starting and ending the string and with the ampersand as a special escape character and you see that the result will be similar. And if I would then read exactly with that manipulator in again this string,
I would again have the same original value I wanted to have. Okay. You might have heard about the literal operator. The literal operator is a new operator introduced in C++11, which is the operator double quotes,
but we call it the literal operator. And it allows me to define type-specific literals. So, for example, I could say, I want to have for complex, for long values,
if I have the suffix underscore i, then this shall be interpreted to be an initial value for complex, for the imaginary part of a complex value. So that I could write something like this. C is initialized by fear plus 7 as imaginary value.
This operator is available in C++11, but with C++14 we have now introduced standardized literals for that. And because user-defined literals always have to start with an underscore, now it's our domain to say, now we can define,
oh, that's the wrong button. Now we can define here in the standard that without the underscore we define suffixes for type-specific literals. And here you see the examples, what you can do right now.
A suffix or S behind this character literal converts this to a std string, which, for example, means that you can do what you see here, that you don't have to convert this explicitly to std string, you do it with the S and then add, for example, another suffix.
And by the way, there must be no space between, so this is an error. Or you can say, I have to pass, I unfortunately have no implicit type conversion from a C string to a std string, so then I could just pass this std string constant with the S at the end.
And this S, by the way, has different meanings. It has meanings for strings, but also for numeric literals. If I put it at the end of numeric literals, it counts as seconds. So this lets me sleep my process on my count thread for 10 seconds. And we use the E, the I, to be able to use it for complex values.
The values initialized, defined, the literals defined are S, applied to string or to a duration,
applied to a numeric literal for a duration. As other literals, we have hour, minutes, milliseconds, microseconds, and nanoseconds. And for complex values, we have I for imaginary part, IL for imaginary part as long,
and IF for imaginary part as float. Ooh, IF, hmm, hmm, that's a keyword, isn't it? Yeah, so we created a special rule in our call language that you really have to define this literal not well,
that you have to put here, we define it that way, no space when we define the operator IF. So the double quotes followed by IF does not count as a keyword IF, but as a literal IF. But that's just implementation sugar of our own keyword.
It's not your problem because you're only allowed to use the underscore in front of these literals. So, then we have also something new, which is called variable templates,
variable templates, not variadic templates. That's a totally different concept. I really hate this wording. I asked, I don't know, a couple of weeks ago in the core team, why did you choose such a strange word? And they say, well, it's a right word because it's a variable that is a template.
So it's not a template that is variable. It's a variable that is a template. Like we have classes that are templates, like we have functions that are templates. So now we can define variable templates. And as I said, don't be confused with the term variadic templates. It's totally different things.
So here you see what it is. You can, for example, say pi is shall be a value where the type is not defined yet. And then I can say I want to instantiate this variable pi with the type double. And that's it. You can even provide default types, as you see here.
So if I say the default type is a long double, then I could instantiate pi with type long double using this syntax. But you have to write it that way. The line below is an arrow.
Okay? And as I said, this is two different concepts. It's not my fault, by the way. Good. So these are just some small changes. Now let's look into a bigger picture we changed in C++14. And I want to start with looking back a little bit
about the history of algorithms and the way to use them. It's a slide concept stolen from Herb Satter. Thanks, Herb. And let's see how C++ evolved over the last years.
So you see here on the top a handwritten loop. And guess we have the task that we have a vector or a collection. And inside the collection we want to find the first element that has a value less than x and greater than y.
So the naive thing, and I must confess I still do that, I shouldn't, yes, Scott, I shouldn't do that, is I program a loop. Yeah, and I just write down what I want to write. So let's iterate over all the elements. We can do it now easier with C++11,
but in the old code we had to do it that way. And let's break the loop when we found the right element, which is the current element if it is greater than x and less than y. Okay, I think everybody can read this line in C++,
can maintain the code, and that's a good thing. So what we learned by introducing the standard template library is, well, but you should better use an algorithm for that. So the algorithm, for example, has or might have some performance advantages.
So the problem, although, was that, yeah, I had to screw up my whole code a little bit. So on one hand I could use the find if algorithm and say, well, let's find the first element that holds a certain predicate, a certain condition,
which returns true or false, and this predicate should check my condition. Well, to check my condition I need access to x and y. So I need a function object, and it's on the right side,
so I have to define a class that behaves like a function, though it defines operator function call, and then I initialize this object with my two elements x and y, which become a and b inside this function object, and I compare each element against these values.
That's nasty programming. It might be faster, but that's close to not maintainable, I claim, because the body of this loop is not available when I want to maintain this code,
and I need at least a comment or a very well name of the predicate to explain what happens here. So to fix this flaw, there were a couple of proposed solutions. Some were in the old C++ standard, some were added by Boost,
and one of the most famous ones was using bind. Well, it might get better for those who are interested in thought experiments, but it might be worse for people who are trying to maintain code for the ordinary average non-expert programmer.
So on the bottom you see the bind way, where you say let's find the first element. Well, let's bind a logical and for bool, because we have to check whether the first parameter is greater than x, and the first parameter is also less than y.
And there are a couple of traps here. The most important trap here is I have to pass the right types here everywhere, so greater uses int because the elements are int, hopefully. If not, that can screw up a lot. And then they both return Boolean values,
and with logical int I process an int for these Boolean values. So that's the new form to program that. I don't do that. Who does? Who uses bind in his production code?
Slow hands, you shame. It's a shame, yes, yes. So the solution is to use lambdas, as you might have heard if you heard C++ 11 already. So now we have lambdas, and now we can use both.
The good performance of algorithms plus inline specifying our criterion, as you see here, for example, saying I want to check, I want to find the first element that holds the condition where the past element, and no iterator or so is involved,
is greater than x and less than y. We need an equal sign here as capture, because this makes x and y available inside the lambda. And there was a nice talk by Herb Sutter. The title of the talk was
Closing Curly Braces, Closing Parenthesis Semicolon. This is the art control delete of C++ programmers now. This is the keystroke you need when you program with lambdas. So that's where we are with C++ 11. So now let's look what changed with C++ 14
and where we provided some enhancements. First, the good news is we fixed, first of all, even with the old style, something. So guess you have a collection, let's use a set,
where you want to sort the elements in opposite direction, so with greater instead of less. The way you can declare that is there on the top, or with C++ 11, you can skip the space between the two closing angle brackets. So now with C++ 14, we have one problem solved,
which is that you have to put the type of the element to the greater predicate, and that is solved. You can now skip this type, and there's a trick, so there's a default type now, void,
and for this default type, there is some magic behind that does the right thing for you. So you don't fall into the trap that the element type doesn't match, and you get extreme awful template error messages
if you screw that up. And you can use it everywhere. Here, for example, you can sort your elements in a vector using the sort algorithm. Again, it's enough to create an instance of greater, so without specifying the type.
And you can even do that, so if you want to use bind, if you still want to use bind, you can also use it with bind to say, okay, now let's bind greater to say, I want to search the first element that is greater than the character string literal A.
Okay, that's first for these function operators. By the way, the title of the paper that proposed this change was named Making Operator Functions Greater, exactly as you see on the top.
So, how do we use Lambdas then? Here's the example. When we switch to Lambdas, we, for example, then can use sort and define our own sort criterion, not just greater or less, but, for example, here,
because I have a class customer where no greater is defined. I define when is one customer less than the other, and I implement it when the first customer number is greater than the other, so it's opposite sorting or inverse sorting according to the customer number,
for example, which I program here. That's C++11. And here, also, the complete example to find the first element that is greater than X and less than Y. Here's the complete example. I have X and Y defined outside the Lambda,
and to use it inside the Lambda, I need access to it, so I pass X and Y as captures, and then I can use this as my criterion. And this is readable, maintainable, fast code. Now I will use algorithms.
However, we have some problems. So one thing is we might need, we might want to capture from the outside into a Lambda something where we want to move semantic, want to have move semantic, so where we want to move the elements into the Lambda.
So here's one example. Guess you create a unique pointer, which is move only, or take any other element you just want to move or have to move. And you start a thread. Here's a thread. And so you need access to this outside unique pointer.
Then you can now specify in a capture to say PTR, so it has a different name inside. PTR is initialized by the moved UP, moved up so by the moved unique pointer into the Lambda. Of course, you have to know what you program there. It has to be correct.
But this is possible now. And you can even, as you see here on the bottom, define your own new capture variables being initialized by some expression you need. Yeah. Yeah, question.
Scott, yeah, I promise, we ask each other. I probably can't answer the question, but tell me.
So the question is to repeat it for those who use the headphones, why did I choose a different name inside the Lambda, PTR, and do I recommend to use a different name than from the outside the UP? And the answer is, first of all, I learned this yesterday,
so I created this slide yesterday, not kidding, because I looked here at the ISO CPP website for the newest features. I didn't know about C++14, so I'm a library guy. I'm not a core guy. And I wanted to demonstrate that you can change the name,
so that's the whole reason. So there is no pattern. Pattern, how to use language features, is the domain of Scott Myers. So buy his next book, and you will probably have an item about that, won't you? Sort of. Okay. Good. So, yeah, you can change the name.
What the exact semantics mean is open, whether it's recommended to have a different name here inside the Lambda than at the outside. That's also something we have to find out. Let me say here something, a little bit off topic of the whole talk. One challenge we face in C++ is
that people come up with new great ideas for both the library and the language. For the library, we usually can try it out first, as long as the library doesn't need new core language features. One famous place to try out new libraries is Boost, for example.
So we have some experience when we standardize it. The problem we face right now is new core features. So people come up with new ideas, like I want to have generalized Lambda captures,
and then they come with a proposal. There might be one or two motivating examples, but we have no clue what this means for C++ as a programming languages as a whole.
So what new patterns apply, how shall we deal with that, etc. And again, in my talk this afternoon, I will explain you, or demonstrate to you, how move semantics screwed up the library,
and how we had to deal with that. There was a new feature, and we had to deal with that, and we had no idea how to deal with that. When we introduce new language features, we usually don't have guidelines how to use these new language features, which is good because sometimes guidelines
are too focused to one application, but which is bad because we have no idea, for example, how to fix or benefit from this feature in the library, and we can't explain to you when and how to use these features. So that's exactly a typical question.
So, aha, I can now use move semantics and captures. Hmm, should I use the same name or not? What is the benefit? What problems might arrive? What tricky problems might arrive? So, that's something for you to find out, or to wait for people who write books and blogs about that.
By the way, this is not a problem we can solve. We have the, well, the other idea, the other approach would be to say there's a cool new language feature, let's try it out five years and then standardize it.
It doesn't work that way. I mean, as soon as compilers have implemented that, they have to be in practice backward compatible even if it's not standardized. So, it doesn't work like that. That's a problem.
Okay. One thing to clarify here is lambdas are function objects. I hope you all know that. And by the way, if you read in the standard the word function object, it implies lambdas. Lambdas is just a shorthand of a function object. So, in fact, when I create a lambda,
which, for example, adds two values, two integer values, as in this example, I indirectly create a new function object which is a new type in its own class named lambda or so, where, by the way, the default constructor is deleted
and where inside I have a function call operator doing the corresponding operations. So, that helps a little bit in understanding for the next slides I have. So, because now we can,
we now have in C++ 11 generic lambdas. Generic, you would expect to have the keyword template, but here the keyword is auto. So, it's a little bit confusing, but there's really a template involved. As you see here, you can say,
my lambda can add two values, but I don't define which argument types are used now. And then, what this is expanded to, logically, is to say I have now my function object where the arguments of a function call
have types which are not defined yet. So, which, in fact, is a template member function. So, then what can you do with that? Can, for example, say, okay, I have here a lambda to the power of three, applicable, callable for any type,
and then I can pass an integer or a double, and I will then expand this to the corresponding operations. I can use it in transform or I can, yeah, period. The last example is not about generic lambdas.
So, and one other thing we fixed in C++14, you can skip the return type in lambdas already. So, you can say, I don't declare return type,
although I have a return statement, but there have been some rules about that, which were, more or less, there has to be one statement that is a return statement. There are small, minor extensions to this rule, but this is roughly the rule. So, for example, the upper example is a correct example,
which should compile. The lower example is not correct in C++11 because it has two return statements. So, now, we have relaxed this rule. Now, in C++14, you can have multiple statements and even multiple return statements.
The only criteria we have is that they all return the same type. And, by the way, this all now is usable in the new function call syntax. So, if we don't need a return type here,
why do we have to specify return types in ordinary functions? That was a question that came up again and again. And now, in C++14, something has changed. So, in C++11, we introduced a new function call syntax saying the return type is at the end of a function declaration.
So, at the beginning, you say return type is auto, and the return type is then after an arrow, which is absolutely equivalent. You can write the thing on the left, you can write the thing on the right, you can even declare the thing on the left and implement or define the thing on the right. It's just two syntaxes for the same thing.
But the new thing now is that you can skip the return type part of the new syntax by saying return type is just auto. And, yeah, compiler, you will find out what it is. It's not a big deal. I mean, two integers multiplied,
the compiler checks, which is the corresponding operator, and will fill in the return type. And same here as a member function to get the price. There are some problem, yeah?
Yeah, there are some rules how to use it about forward declarations and contradictions, et cetera. So, I would say, roughly, the compiler has to know the magic how to find out the return type, and it's not allowed to have a contradiction.
So, yeah, so, but, yeah, I don't know, and I'm not able here in this short of time to show you the detailed rules, just as a general rule where we go to with C++14. Good. And there is also now the ability even to say
if we return something, the type remains as it is, which is called decltype auto. See here the following example on the top. We have a function returning a value by value,
and we have something returning a string reference. So, now let's call these two functions by our own function, and the problem is, by rule, that it's a problem to have the correct type here returned. In fact, you would need for one, for the second call,
you would have to specify that the return type is string ref, and for the first function it's string. And now you can deduce this by saying decltype auto. It's also, it automatically deduces to the right type
by value, by reference, or whatsoever. So, this is important to forward arguments through function calls. And, by the way, be careful about the detailed core rules. There's one problem I learned, I didn't have the experience yet, but I learned it,
is, for example, see at the bottom, we have here just the same function. The only difference is that the return statement uses parentheses around the return value. This changes the return type.
And, by the way, so that the letter is probably an error because you returned the reference to a local object. For rules about type deduction, I refer to Scott Meyer's talk, one of your two talks, it's the next one or the second one? This afternoon. This afternoon is about the detailed rule of type deduction.
I just say here that we now have this ability as a language feature. Good. So, that's it. Now, we have a couple of bug fixes in the standard library and in the standard, but especially in the standard library, and I want to show you one example
how we work in practice and what we find and fix. So, this is for you. Here's an example. You might have heard about the new feature of initializing by initializer list. Unfortunately, we might have a problem. We can say we initialize values or objects
by an initializer list of int or by a single int, so we have an ordinary constructor. So, my question is, think a little bit and tell me which of the two constructors is called for initializing A, B, and C?
Think of it. I'll give you ten seconds. So, the answer is none of this calls the initializer list constructor because it uses the old non-braced initialization way.
However, so let's use the new way to initialize values with braces, with curly braces. So, the question is D, E, and F. Which constructor is called for initializing D with no argument,
E with one int argument, and F with two int arguments? Here's the result. Did you get it? Because there's a special rule.
In general, initializer list constructors strike ordinary constructors when using brace initialization, but as a special rule, if you have a default constructor, that strikes everything else. So, that means D is initialized by the int constructor
because it's a default value for int, and the other two, E and F, is initialized by an initializer list. Okay? That's C++11. So, now let's put an equal sign here. So, now think about that. How does it change the semantics?
G, H, and I, are you using the same rules in overload resolution than D, E, F, or something different? Who think it's the same rule, that the same rules apply? Who think that different rules apply?
Oh, a lot of people have no opinion. Or too lazy? Too lazy. It's the same rules, by the way. Well, hmm, yeah, hmm, yes and no. It's the same rules, but. Now let's put, ah, and this, by the way,
is a consequence of that. If you declare a vector, and you initialize it with 3 and 42, a vector of int, and you use parentheses, you get a different result than if you're using curly braces. The first form is the old constructor,
creating three elements of the value of the second argument. And the second initialization is initializing a vector with the values 3 and 42. So now, let's think about explicit. You have heard about explicit?
Explicit here, if you have a collection, and you can explicit, or you can create a collection by passing an initial size, then it's important to place explicit here, because you have then no implicit type conversion from an int to a collection,
so that if you have declared a function foo, taking a collection, and you pass just 42, it doesn't silently convert to a collection of 42 elements. So you have to explicitly convert this type. And again and again, I have to tell
that this has an impact on initializations where the equal sign is used. So without the equal sign, we have direct initialization with the equal sign. We have so-called copy initialization, which does not call the copy constructor, but has special rules. So here you see how it works.
C1, C2 is the initialization of the collection with the value of 10. Old syntax, new syntax. So we create a collection with 10 elements. If I use the copy initialization, which is the initialization with the equal sign,
then this is forbidden due to the explicit above. And you have to explicitly convert to a collection. OK? That's old stuff. That's C++03, or with the curly braces, 11 stuff.
Now let's go back to our example and put an explicit here. So let's see whether you learned your lesson. ABC is initialized by constructor,
the ordinary constructor, no curly braces, so no initializer list is used, but using the equal sign is an error due to the explicit. OK? So next example. Oh, as before, curly braces use the initializer list
constructor unless it's a default constructor. So now let's use the equal sign. Oh, yeah. Because the first initialization expands
to the default constructor, which is explicit, now the first initialization is not allowed. If I would not have a default constructor, the first initialization, so the initialization of G, would call the initializer list constructor. So why I am telling you this stuff?
Well, this doesn't look as a serious, well, as a useful behavior. I mean, in principle, initializer lists imply a list which has no element. And if you can pass an arbitrary number of elements
to something, there should be no special roots for passing no element. So we have that, unfortunately, in the standard in C++ 11. So in C++ 11, we define the constructors for vector to be the default constructor for vector being explicit
and the initializer list constructor to be not explicit. Of course, the constructor shall be explicit because we don't want to have a silent conversion from an allocator to a vector.
Yeah, so it comes from the old days where explicit did only matter if you have one element for initialization. But now with C++ 11, explicit matters for zero, two or more arguments even.
So that has, for example, this interesting problem. Jonathan Wakely and Marcia Klaw told this to the library working team where we discuss bugs and features and how should we fix them. And that was the example here on the bottom.
There was somebody taking a variadic template, so taking an arbitrary number of arguments, and then use this to initialize V with all the past elements. But unfortunately, he used the copy initialization, so the equal operator here.
So this worked if I passed one, two or three elements, but it didn't work if I passed no element. Well, then it didn't compile. You can consider this as a feature, but we consider this as a bug. So we fix that, and you will, for example, find in C++ 14 a changed declaration of class vector
where we now have split up the constructor taking an allocator with a default argument so that it also serves as a default constructor. Now this constructor has become two constructors
for each container class. So we now have a non-explicit default constructor for vector and all the other containers, and we have an explicit constructor taking an allocator. And that's by the way probably also something we learn, again, as a pattern.
Don't, don't implement the default constructor by using default arguments from another constructor because not only because of explicit, but also because of exception safety guarantees and const expressionness.
It's always a special case, and especially the default constructor should always match to an initializer list constructor if you have both, which is not a rare case in container classes. Again, something for a book. Finished your new book already?
You have a question? Yeah. The question was is this fixed just by this change
to the vector class and not by changing the overloading rules? And the answer is yes. So we changed that in all allocators, but we still think there are some things screwed up with explicit in the library. So there might be other examples like that,
but this was the worst example we had. So we fixed that for C++11. And by the way, I am proposing for C++17 that explicit has no effect anymore to copy initialization.
So that there's never a difference between assigning, between using an equal initialization or not if you use curly braces. It should still apply the old rules, but here there should no longer be a difference. That's my proposal. Let's see whether that will be accepted in C++17.
Good. So some minor stuff at the end of this talk. We have some other stuff I just mentioned. So like make-shared, now we have a make-unique. We have new arguments for three algorithms,
which is equal, mismatch, and is-permutation. These three algorithms take two ranges because you compare two ranges and find and check whether they are equal or whether one is a permutation of the other or whether there's a mismatch.
And so the problem was, as usual, you passed the first collection with begin and end and the second only with begin, which meant you had first to find out which one is a smaller collection. And that's pretty expensive.
So we have now an overload that allows that you pass begin and end of both collections you compare and that the comparison ends when the end of the smaller collection is reached. We have a generic integer sequence interface and we have a minor fix.
I will also give an example how to use it later on in the afternoon talk, which is instead of writing a so-called type trait, which, for example, in a template removes constness from a type, where I have to write std remove const,
then my type name, colon colon type, and because type is a type name, type name in front of this expression. Did you get that sentence? Okay, so this can be replaced now in C++14 by class remove const T, the whole expression, which is a lot shorter and makes life a little bit easier
for those who program templates and generics. And finally, we introduced a new attribute. So we can now formally specify that a feature in C++14 or in C++ in general
is deprecated so that we have a formal way to, for example, create compiler messages. For example, a compiler vendor could implement get S with the command this is deprecated, use that and that instead. And by the way, there's a story behind get S is,
in fact, not only deprecated in C++14, it's removed. We have, for the first time, we have officially removed a feature in C++ by removing get S. We have deprecated a couple of things, but this is officially removed because there is no way to use gets in a safe way.
So it's, by the way, it's also removed from the C star net. So ideally it should not even compile, but yeah, compiler vendors always try to support backward compatibility so they might be instead declared
like that, deprecated, use that and that instead so that you get a compiler warning. Okay, that's it. That's it for one hour I have. So I hope you got some insights, some new insights about C++14,
maybe some new insight about C++11. And now have fun with all the other talks. Scott is next and then Andre is there. So have fun for the rest of the day. And yeah, thank you very much.