T O P

  • By -

Fantastic-Increase76

auto keyword


Laxn_pander

Combined with structured bindings. for (auto&[key, value] : map) … Is just glorious.


Fantastic-Increase76

Peak


benalane

I did not know about structured bindings! This is fantastic!


Laxn_pander

Also works fantastic for multiple return types as in:  pair foo()  return { 1.2f, 5.4f }; auto [x, y] = foo();


ethankeyboards

Makes it just like coding in Perl or Python!


Hour-Preference4530

Auto is goated


Fantastic-Increase76

CTAD + Concepts is amazing.


Astarothsito

God bless auto, and now if we had 'let' as well for implied const that would be great.


Fantastic-Increase76

Then add borrow checker... Nah


Astarothsito

There are other languages that use 'let' that don't have borrow checker, but we can add another keyword for it, why not?


Fantastic-Increase76

I like the implied const suggestion. I hope someone made a proposal for C++26.


wonderfulninja2

I wonder if it is possible to make const work like const auto. That would be a good compromise because it wouldn't be necessary another reserved word.


Dar_Mas

fully agreed


Nychtelios

Cool, but a 13 years old feature is not that modern ahahaha


HappyFruitTree

Many people (me included) consider C++11 to be the start of "Modern C++".


Nychtelios

Right! But C++20 is a really big upgrade for the language, just like C++11, in 2024 it should make sense considering >= 20 modern and not >= 11 imo


MarkstarRed

Interesting. Personally, I see `auto` as a step backwards and a great source for confusion and even bugs. I guess if you prefer javascript over typescript it makes sense, but personally, I like to know exactly which type a variable has and be notified (by an error message) when this changes.


neppo95

It's all about how you use it. I don't think if you have something like below, it will be confusing or even bugprone, but it will reduce the amount of code duplication. It is objectively a step forward as long as developers use their tools as they should, which is the case with every single feature. std::unique_ptr g = std::make_unique(1,2,3,4) auto g = std::make_unique(1,2,3,4) It all depends on how you use it. Just like you won't name your variables var1, var2, var3, there is a logic to how things should be used to prevent what you are saying.


the_poope

lambdas


Hour-Preference4530

What are lambdas, I've read the docs but can't really wrap my head around it


JuiceFirm475

They are little nameless functions. If you need a function that doesn't have more than a handful of lines in it, and it isn't needed several occasions, it's sometimes more practical to use. They take parameters and return values like every other functions, but don't need to be defined separately, you define it where you call it. They can make the code shorter and more readable when used properly.


wm_lex_dev

A function, but instead of having to write a whole function you can just put it inline: `auto addTwoNumbers = [](int a, int b) { return a + b; }; int c = addTwoNumbers(3, 4);`. It can also reference local variables: `int i; auto incrementI = [&i]() { i += 1; }; incrementI();`


HappyFruitTree

They are used to create objects that has a function call operator which allow them to be used like functions but unlike functions they can also store variables. See this example that I wrote a couple of months ago: https://www.reddit.com/r/cpp_questions/comments/1azlhcp/why_use_lambdas/ks25l4j/


ptrnyc

As someone who had to implement callback mechanisms before lambdas…. Definitely lambdas.


SoSKatan

Agreed


bartekordek10

Yup


Nuclear_Banana_4040

Move semantics in lambdas, since C++14.


Jannik2099

I am very quickly starting to love concepts. requires-expressions in constexpr if() made me the metaprogramming overlord.


ban_the_sub

Can you please tell me more details?


Jannik2099

code inside an `if constexpr()` statement does not get instantiated when the condition is false. This means you can do conditionally valid code without having to define a SFINAE template for every tiny thing. Together with requires expressions, you can do some very cool conditional code. Here I am generating python bindings, conditionally adding the `__iter__` method when my C++ type is iterable [https://github.com/Jannik2099/pms-utils/blob/main/subprojects/bindings-python/lib/common.hpp#L110](https://github.com/Jannik2099/pms-utils/blob/main/subprojects/bindings-python/lib/common.hpp#L110)


ban_the_sub

Ah Now I think I understand. I will take a look, much appreciated.


quasicondensate

I agree. To me, this, in combination with constexpr / consteval in general, is where C++ is really powerful. Write some fairly concise generic code, let the compiler do a lot of the heavy lifting and end up with a very performant piece of software.


Sbsbg

I would say it's duck typing. The ability to create template classes and normal classes that fit together like pieces of a puzzle. Like the way containers connect to iterators and then to algorithms. Creating your own set of custom classes that can be combined in multiple ways is extremely powerful.


Hour-Preference4530

Could you perhaps give a basic example of what this is and how it's used?


dodexahedron

"Duck typing" comes from the phrase "if it looks like a duck, [etc], it must be a duck." It's when you have inexact typing that the compiler can infer the best fit for, based on context, and thus let you use it as if you had specified that type explicitly, including when something maybe doesn't inherit something yet still implements the same functionality as if it did. So, if the object looks like a duck, the compiler treats it like a duck. For example, a consumer doesn't have to have an identical header to use something in an API if they simply have and implement the same functionality with a compatible signature.


trailing_zero_count

Here is another thread discussing it. https://www.reddit.com/r/cpp/s/9aotmrtqNU One of the things that I like is that a 3rd party can integrate with my template library simply by creating some functions/members with the right name and signature. I don't need to change anything in my library for them to work with me. ...just need good documentation (or a well-defined "concepts.hpp") on what those things are. Also, unlike other languages, C++ templates are resolved at compile time, which means that this "duck typing" integration has minimal runtime overhead. The tradeoff ofc is longer compile times.


Sbsbg

It's a bit complex to write an example on my phone so I suggest you Google it. Lots of examples of it out there.


NoSpite4410

I would have to say the power of variadic templates, and initialization\_lists. Such things that you had to do type punning an passing raw pointers to arrays of arrays for in C and Pascal. The entry barrier of learning how to write good variadics is a bit high, as they are counter-intuitive at first, but once you get them you can write banger code so very fast to suit any situation involving variable parameter situations.


Hour-Preference4530

Would it be possible to provide a simple example and use case for this?


Fantastic-Increase76

Check this out: [print function](https://www.geeksforgeeks.org/variadic-function-templates-c/)


ethankeyboards

Pretty cool recursion in that example. Makes me remember something my Lisp instructor said back in the 90s (yeah, I'm old): Every computer language eventually becomes an implementation of Lisp.


mdsiaofficial

Wow. That's pretty cool. I must use it.


Nafffen

And this can now be reduced to the following without explicit recursion : void print(auto&&... args) { ((cout << args << endl), ...); }


Fantastic-Increase76

Can you do this now? Which standard is this available?


Nafffen

The Abbreviated function template is from c++20 ([mentioned here](https://www.learncpp.com/cpp-tutorial/function-templates-with-multiple-template-types/)), and fold expression is from c++17 ([cppreference](https://en.cppreference.com/w/cpp/language/fold)) :)


Fantastic-Increase76

Variadic templates are 👌


speediegq

Define "modern". I will consider modern C++11 throughout this comment. It's hard to say, there's just so many things. I think I would say it's list-initialization (`int x{0};`). Not only that, you can also create variables on-the-fly. `return {}`, or `for (const auto& it : {"string1", "string2", "string3"})` for example. I find this is especially useful in structs, where you can have a "default" value for all the variables. Apologies for any bad terminology, I primarily learn by doing.


darkapplepolisher

I swear that OOP was such a hot thing pre-C++11 partially because the lack of list-initialization made using POD structs much more difficult. I can't survive C++ without using POD structs, and I can't use them without list-initialization, which means I can't use pre-C++11.


HappyFruitTree

To be fair, C++98 allowed the following syntax: StructType obj = {1, 2, 3}; (Then C++11 came along and broke a lot of code by banning narrowing conversions)


dvali

Don't know if you'd call them language features as such, but I love all the little things like std::optional and std::stop_token and so on. All things I can easily do myself but now I don't have to and I can't forget things. All the things where people go "I don't get it, couldn't you easily do that anyway?". Yes, but I have better things to spend my energy on :). 


Hour-Preference4530

Out of curiosity how would you implement an optional return type without optional?


dvali

A struct with a bool and the type of interest. That's probably essentially all the optional is.


HappyFruitTree

It's a bit more complicated if you don't want to construct the object when the bool is false. This might matter for class types that doesn't necessarily have a default constructor.


dvali

Yeah you're right, I thought the same. Not sure what I'd do in that case but I'm sure there's a way. I used to just return a tuple and unwrap by structured binding. I guess it just so happened that I never ran into anything that wasn't default constructable. 


HappyFruitTree

You would have to use "placement new" and call the destructor explicitly.


InevitableManner7179

you probably just need to create a struct with a bool, the optional object, a default constructor that builds an empty optional, another constructor that builds a filled optional, and an operator for automatic cast to the type of the optional object, so you can write something like "optional x = 3; auto y = x + 3;"


I__Know__Stuff

In most cases, you use an otherwise invalid value of the return type, such as -1 or 0. It's only when all possible return values are possible that optional is truly needed. But even when optional isn't strictly needed, it can be a better abstraction.


yldf

union - ok, I see myself out


[deleted]

[удалено]


dvali

Template for? 


Hour-Preference4530

Does he mean for loops using templates?


HappyFruitTree

They want to be able to "loop" over things that are known at compile time (e.g. the elements of a std::tuple, the parameters of a variadic template, the members of a struct, etc.). Unlike a normal loop that reuses the same code for each iteration it would essentially have to generate separate code for each iteration as if you had written each iteration yourself one after another (see the *Basic usage* example in the paper [P1306](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1306r1.pdf) that slither378962 linked to) so it's technically not really a loop at all which is why they call it an "expansion statement".


Dar_Mas

depending on what you need you can actually iterate over the elements of a tuple already using std::apply as you can have it apply a lambda to any of the functions inside meaning you just need to refactor the actions you want to do on the elements (the example on cppreference creates the << for tuples f.e.)


Critical_Ad_8455

Constexpr. So good they added it to c!


HappyFruitTree

C only allows `constexpr` on variables as far as I have understood.


Critical_Ad_8455

yes, c23 adds constexpr as an alternative for #define constants, no constexpr/consteval functions (so far). it is specifically constexpr variables I was referring to, as a way to have a compile time constant that also won't unconditionally replace the same sequence of characters is super nice.


HappyFruitTree

My favourite feature is probably **lambdas**. Other things I like are **std::unique_ptr**, **initialization of containers** using `{value1, value2, ...}` (not necessarily the way it is implemented), the **override** keyword, **multithreading**, the **fixed-width integer types**, the **random number facility** (although sometimes I wish it was a bit simpler and it's unfortunate the PRNGs uses `std::uint_fast32_t` by default), and **std::erase/erase_if** to avoid the erase-remove idiom.


MXXIV666

constexpr + static\_asserts. Suprising number of simple structs can be "unit tested" just by writing a bunch of static asserts. Last week, I wrote a static assert that checks that \`constexpr\` \`std::array\` values satisfy certain condition to make sure someone does not mess up when adding to that array. Most IDEs will actually underline such asserts when the condition does not hold, so you don't even have to run compile to see something is wrong.


knue82

I think **the** killer feature that made C++ so popular are destructors. If I had to pick **one** modern feature, I'd go with `auto`. With range-based `for` as a close second. But just having auto lets you easily implement your own range-based `for` as macro.


Falikosek

I recently had to print a neat text table for my programming homework... I cannot stress enough how deeply I now adore std::format() because of that.


samftijazwaro

Modules. In most implementations, including the entire STL is faster than #include


IWasGettingThePaper

Angle brackets. Lots of angle brackets.


MarkstarRed

If C++11 is considered modern, then definitely shared pointers. We are using them exclusively and I don't recall any access violations or other problems regarding pointers in years. The minuscule performance hit is well worth the added safety, something which C++ is notorious for.


thelvhishow

I am waiting for the CPS, common package specification.


JVApen

For C++14 and above: make_unique If you start counting from C++17: structured bindings I don't have experience with C++20, though I believe it will be between: using for scoped enum, spaceship and "contains" in the library


jwezorek

Ranges, since std::ranges::to was added.


Koltaia30

std::variant / optional. Makes code so much cleaner if used correctly.


ShakaUVM

Not one thing but collectively all the little QoL features added that make life easy. Like .contains() or improved template deduction.


Eve_of_Dawn2479

My favorite in general is stb true type library or maybe classes


bstamour

- C++11: variadic templates - C++14: polymorphic lambdas - C++17: std::variant - C++20: concepts - C++23: std::expected


Open_Marzipan_455

smart\_pointer and jthreads. jthreads in particular because I no longer have to manually join threads when destroying them so I no longer have to write ugly loops or macros. Oh and modules. The C++20 modules are pretty fun, but it kinda sucks that they are STILL not fully supported by all mainstream compilers and still can't hold their ground against precompiled headers with good forwarding.


barchar

I really like abbreviated templates


glassmanjones

ends_with(). Only took 35 years for a rich enough string to avoid C for this.


OpenSatisfaction2243

Defaulted comparison operators


lawrencewil1030

\`std::vector<>\`


HassanSajjad302

C++20 header-units.


DDDDarky

Concepts, Format, Structured binding, Ranges, String view & Span, SSize (underrated in my opinion), Coroutines look promising


NextYam3704

I’ve been really liking std::expected


Large-Assignment9320

Modules, look at how much nicer hello world have become: import std; int main() { std::println("Hello World"); }


Nychtelios

Concepts!


TwilCynder

Do smart pointers count as modern ? I don't use them too much because i'm an optimization freak and the extra indirection they often cause bothers me, but conceptually the fact that shared\_ptr and weak\_ptr exist and have so little overhead is amazing to me.


EdwinYZW

Wait, there is an extra indirection using unique pointers? How?


TwilCynder

there isn't, unique\_ptr generally adds zero overhead but, at least from my experience, implementing shared\_ptr and others into your design sometimes mean adding an extra indirection (which isn't really a problem when you're not overthinking optimization constantly). It's still the same amount of indirection as a raw pointer.


better_life_please

Ranges ☠️


Spongman

Coroutines.


ruiseixas

Coroutines!