I just now realize how many C++ 17 features I already took for granted. Structured bindings and if with initializer are big ones. I use the modern if all the time. I wrote a lot of Go before C++ 17 so I was very happy to see C++ finally adopt that feature. Stringview is the one thing I have never used so far I'll have to try it out some day.
I don't use binary literals all that often, but if constexpr is a time/code saver. Being able to write one function and just have it switch on a type for example ( if constexpr( std::is_integral_v ) else if constexpr( std::is_floating_point_v )... Makes life grand. The nested namespace is also very nice, but I think it can be cleaner to have actual nested namespaces in some cases, but I'm glad the feature is there.
Just want to remind that "inline static" for static members happened in c++17 also No more need to create nice class only to add some additions outside of it just for sake of it
I used to work with C++ quite a lot in the 90's. For the last 15 years I have worked mostly with C and Java. I am now looking at C++ again for a big project and thinking that the people governing the language have taken a difficult language, made it more difficult and then wrapped it in impenetrable nomenclature for good measure. So, back to C I guess.
I'm surprised `if constexpr` didn't make the list, given its ability to, in some cases, completely remove SFINAE overhead. I really like if-init because it reduces scope, but I really hate it because no matter how you format it, its presence really interrupts the flow of reading code.
Nice additions but for me the clear winner is the parallel STL. In general C++ is still lacking in libraries which is a weak spot compared to Java and .NET when you are developing applications.
Hey Jason, trying to find an entry point for C++ from being a designer for years. I like your teahing style but cant find an entry point. Even with this video im not sure many of the terms you're referring to. Do you have any videos that are even more basic as a starting point?
My main recommendation is A Tour of C++ for a high level overview of the language. Unfortunately I don't have the channel organized very well for beginners, but it is on my to-do list to make a playlist for that purpose.
yup so much cleaner, std::map::try_emplace(key, ctor_args) is also a beauty imho, which otherwise is a few lines to express: if this key exists, give me the element, if it doesn't yet, create it and give it to me. Especially when initializing a map in a loop, this is much cleaner and so intuitive. For the c++14 code I still have to work on I created a free function that does something similar (I never identified this as something to extract until I saw this member function.. shame on me!)
@@OmarChida Oh god, your comment reminded me that I used to watch Jason, and couple other guys, while learning modern c++. I wasted so much time trying to learn it instead of actually doing interesting shit; I wouldn't touch that shit again with a mile long insulated stick now.
@@Mr4NiceOne I myself was an Ultra-Orthodox C++ programmer been using C++11 for years now. It's just since couple of months that I started really modernizing my knowledge since I saw some useful features in the new standards.
At the end of the video he says when he writes 'void func()' we're accessing the global scope, don't write code like this. What is he referring to here and why shouldn't it be done?
He says: "we are accessing the global(ly defined) values", which is basically the same as you said of course. In this case, the function could be better if it got a reference to 'a' values pair via its function arguments, and for example define the pair in the main function in stead of the global scope, and pass it to func(values) when you call it. The advantage would be to decouple the function func from the global variable instance, so it could be (re)used in other contexts, for example it is then much easier to test in a unittest: unittests typically reinitialize all variables for each testcase, but with global state, this state is defined/initialized once for the unittest executable and then reused for each testcase/section/.., so you'd have to reinitialize/clear it explicitly in each testcase, which is usually error prone, and generally it is a good principal in unittests to keep each testcase completely independent, as the order of testcase execution could otherwise have influence on the outcome of the testcase.
@@frydac To clarify, you're saying that he is saying something like the example below would be better code, because values is allocated inside the main function's stack frame, and that it would be able to be used in any instance, using any pair given to the function? Are there performance or other related issues with global state, or is it just that the memory is not freed by the operating system until the program ends? #include void func(const std::pair &pair) { if (auto [first, second] = pair; first > 5) { // Do important work } } int main() { std::pair values{1, 2}; func(values); }
in many graphical user interface libaries a basic building block is called a 'widget', the gui is then composed of a hierarchy of widgets representing the different 'drawable' elements of the gui. To implement different concrete gui elements, one would derive from such a widget and implement specific draw/resize/... functions. Then to decouple the exact type of the widget, e.g. Button, MyInputForm.. from the code managing the hierarchy, a factory can be used that will construct the concrete type internally but returns a (owning) pointer to the base widget type to compose this hierarchy with, and use it for e.g. drawing/resizing. In this way when the implementation of the specific widget is changed, this code would usually not even have to be recompiled. Imho, this is why he used it as a typical example of a factory function creating something and returning that something which also passes ownership to the caller of the function, and for which you can now be sure no copy nor move is happening under the hood. This has been an optimization in C++ compilers for longer that 20years, and maybe much longer (I recently read about it in 'Inside the C++ object model' from '96, very good book btw!), but this was not guaranteed, in certain circumstances the optimization would not happen (e.g. multiple return statements in the factory function) so you'd have to know your compiler's implementation/rules to know for sure it was elided.
Why are we even forced to write "constexpr" everywhere anymore? Wouldn't it make more sense to just make it the default, and add some uglification if for some odd reason there's something that must not be evaluated at compile time? In a few years' time I guarantee that this will be thought of as one of the ugliest warts of the language.
@@vorrnth8734 The compiler has always been allowed to evaluate constant expressions at compile time. C++11 constexpr just added a set of constraints that gave compilers a minimum set they had to be able to handle. Every standard version since has loosened the constraints further, and we're now almost at the stage where the whole language can be used. But if you follow the "constexpr everything" mantra in your code, then it becomes completely redundant, just adding more visual noise.
@@vorrnth8734 The compiler needs to check anyway if it actually can evaluate a constexpr function at compile-time -- and it is legal to mark functions constexpr, which never will actually be constexpr (e.g., godbolt.org/z/lLjXNF), so the standard could have said as well, something like "If you assign something to a constexpr variable, let the compiler figure out, if it can evaluate it at compile-time". Of course "what the compiler can evaluate at compile time" needs to be specified rigorously (I did not fully think this through, I guess this could still break something, maybe some SFINAE constructs will break). I do fully agree that not breaking existing code is a very important feature of C++
Your videos are very cool but I'm kinda novice in C++ so I would like your explanations could consider that many viewers are not advanced, because if someone is advanced he may not need tutorials right?
I just now realize how many C++ 17 features I already took for granted. Structured bindings and if with initializer are big ones. I use the modern if all the time. I wrote a lot of Go before C++ 17 so I was very happy to see C++ finally adopt that feature. Stringview is the one thing I have never used so far I'll have to try it out some day.
There are some more important features as well
1. Binary literals
2. if constexpr
3. Nested namespace
Isn't binary c++ 14?
I second the Nested namespace thing... very handy!!!!!
@@donaldherman1741 :- Yes, You're right my mistake.
@@Embedonix Agree with this. Having to manually nest namespaces is a PITA.
I don't use binary literals all that often, but if constexpr is a time/code saver. Being able to write one function and just have it switch on a type for example ( if constexpr( std::is_integral_v ) else if constexpr( std::is_floating_point_v )...
Makes life grand.
The nested namespace is also very nice, but I think it can be cleaner to have actual nested namespaces in some cases, but I'm glad the feature is there.
Awesome! Thank you Jason. ❤
Another great episode! Every time I see the notification for C++ weekly I am "Guaranateed" to learn something.
I love the features that makes meta programming more "normal." Fold expression belongs to that category.
If a meta-programming hack is widely used enough, then a language feature should replace that.
Just want to remind that "inline static" for static members happened in c++17 also
No more need to create nice class only to add some additions outside of it just for sake of it
yes! especially in a non-template header only small class, for which you then have to make a translation unit to initialize the static member.
so far, 3 people have confirmed they are using c++98
4 people by 2021...
Every language has added structural binding.... welcome to the club C++17
Structured bindings! I didn’t know that was a thing!!
at 0:40 subtitles say "The number one thing that I want to mention is guaranteed COPULATION"... I knew C++ was the right choice for me
the very chaotic template function adds things then returns them from Maine
Awesome content !!
I used to work with C++ quite a lot in the 90's. For the last 15 years I have worked mostly with C and Java. I am now looking at C++ again for a big project and thinking that the people governing the language have taken a difficult language, made it more difficult and then wrapped it in impenetrable nomenclature for good measure. So, back to C I guess.
Is there a way to, or has there been discussion around structured bindings without hiding the types? Some way to write [ int x, int y ] = my_point;
I'm surprised `if constexpr` didn't make the list, given its ability to, in some cases, completely remove SFINAE overhead. I really like if-init because it reduces scope, but I really hate it because no matter how you format it, its presence really interrupts the flow of reading code.
What about for loops :^)
Nice additions but for me the clear winner is the parallel STL. In general C++ is still lacking in libraries which is a weak spot compared to Java and .NET when you are developing applications.
8:40, would C++17 accept *std::pair values {1,2}* , deducing the template args?
Yes
Hey Jason, trying to find an entry point for C++ from being a designer for years. I like your teahing style but cant find an entry point. Even with this video im not sure many of the terms you're referring to. Do you have any videos that are even more basic as a starting point?
My main recommendation is A Tour of C++ for a high level overview of the language. Unfortunately I don't have the channel organized very well for beginners, but it is on my to-do list to make a playlist for that purpose.
I just wish structured bindings had a way to tell it that one element isn't used, i.e. to silence the -Wunused* warnings
For std::array is it possible to only deduce the size and not the type?
Unfortunately not
guarana-teed 🍒💪😤
I think you forgot constexpr if
C++ 17 feature I use the most is:
auto & f = foos.emplace_back();
yup so much cleaner,
std::map::try_emplace(key, ctor_args) is also a beauty imho, which otherwise is a few lines to express: if this key exists, give me the element, if it doesn't yet, create it and give it to me. Especially when initializing a map in a loop, this is much cleaner and so intuitive. For the c++14 code I still have to work on I created a free function that does something similar (I never identified this as something to extract until I saw this member function.. shame on me!)
Had that in my own standard library that I wrote 3 years ago
@@OmarChida Oh god, your comment reminded me that I used to watch Jason, and couple other guys, while learning modern c++.
I wasted so much time trying to learn it instead of actually doing interesting shit; I wouldn't touch that shit again with a mile long insulated stick now.
@@Mr4NiceOne I myself was an Ultra-Orthodox C++ programmer been using C++11 for years now. It's just since couple of months that I started really modernizing my knowledge since I saw some useful features in the new standards.
What is the scratchpad tool? Love seeing the asm at the right to verify what is happening.
compiler explorer godbolt.org
I m really i want to bay your book 📖
Your are very awesome son
Is there ebook.
leanpub.com/cppbestpractices
Also the flag "-fno-elide-constructors" does not work anymore, right? It is now guaranteed.
c++ veteran: here's the new code, totally idiomatic with latest features
newbie: wtf
At the end of the video he says when he writes 'void func()' we're accessing the global scope, don't write code like this. What is he referring to here and why shouldn't it be done?
He says: "we are accessing the global(ly defined) values", which is basically the same as you said of course.
In this case, the function could be better if it got a reference to 'a' values pair via its function arguments, and for example define the pair in the main function in stead of the global scope, and pass it to func(values) when you call it. The advantage would be to decouple the function func from the global variable instance, so it could be (re)used in other contexts, for example it is then much easier to test in a unittest: unittests typically reinitialize all variables for each testcase, but with global state, this state is defined/initialized once for the unittest executable and then reused for each testcase/section/.., so you'd have to reinitialize/clear it explicitly in each testcase, which is usually error prone, and generally it is a good principal in unittests to keep each testcase completely independent, as the order of testcase execution could otherwise have influence on the outcome of the testcase.
@@frydac To clarify, you're saying that he is saying something like the example below would be better code, because values is allocated inside the main function's stack frame, and that it would be able to be used in any instance, using any pair given to the function? Are there performance or other related issues with global state, or is it just that the memory is not freed by the operating system until the program ends?
#include
void func(const std::pair &pair) {
if (auto [first, second] = pair; first > 5) {
// Do important work
}
}
int main() {
std::pair values{1, 2};
func(values);
}
Excuse me ? What is a widget?
just a "thing"
in many graphical user interface libaries a basic building block is called a 'widget', the gui is then composed of a hierarchy of widgets representing the different 'drawable' elements of the gui. To implement different concrete gui elements, one would derive from such a widget and implement specific draw/resize/... functions. Then to decouple the exact type of the widget, e.g. Button, MyInputForm.. from the code managing the hierarchy, a factory can be used that will construct the concrete type internally but returns a (owning) pointer to the base widget type to compose this hierarchy with, and use it for e.g. drawing/resizing. In this way when the implementation of the specific widget is changed, this code would usually not even have to be recompiled.
Imho, this is why he used it as a typical example of a factory function creating something and returning that something which also passes ownership to the caller of the function, and for which you can now be sure no copy nor move is happening under the hood.
This has been an optimization in C++ compilers for longer that 20years, and maybe much longer (I recently read about it in 'Inside the C++ object model' from '96, very good book btw!), but this was not guaranteed, in certain circumstances the optimization would not happen (e.g. multiple return statements in the factory function) so you'd have to know your compiler's implementation/rules to know for sure it was elided.
std:any
Why are we even forced to write "constexpr" everywhere anymore? Wouldn't it make more sense to just make it the default, and add some uglification if for some odd reason there's something that must not be evaluated at compile time? In a few years' time I guarantee that this will be thought of as one of the ugliest warts of the language.
DMStern It could break existing code.
What Vornth said. No need to turn C++ into Python (version wise).
@@vorrnth8734 The compiler has always been allowed to evaluate constant expressions at compile time. C++11 constexpr just added a set of constraints that gave compilers a minimum set they had to be able to handle. Every standard version since has loosened the constraints further, and we're now almost at the stage where the whole language can be used. But if you follow the "constexpr everything" mantra in your code, then it becomes completely redundant, just adding more visual noise.
If it can be evaluated at compile time, the compiler will do it often anyway, it is called optimization.
@@vorrnth8734 The compiler needs to check anyway if it actually can evaluate a constexpr function at compile-time -- and it is legal to mark functions constexpr, which never will actually be constexpr (e.g., godbolt.org/z/lLjXNF), so the standard could have said as well, something like "If you assign something to a constexpr variable, let the compiler figure out, if it can evaluate it at compile-time". Of course "what the compiler can evaluate at compile time" needs to be specified rigorously (I did not fully think this through, I guess this could still break something, maybe some SFINAE constructs will break).
I do fully agree that not breaking existing code is a very important feature of C++
Your videos are very cool but I'm kinda novice in C++ so I would like your explanations could consider that many viewers are not advanced, because if someone is advanced he may not need tutorials right?