C++ Weekly - Ep 414 - C++26's Placeholder Variables With No Name
Вставка
- Опубліковано 4 лют 2024
- ☟☟ Awesome T-Shirts! Sponsors! Books! ☟☟
Upcoming Workshop: Understanding Object Lifetime, C++ On Sea, July 2, 2024
► cpponsea.uk/2024/sessions/und...
Upcoming Workshop: C++ Best Practices, NDC TechTown, Sept 9-10, 2024
► ndctechtown.com/workshops/c-b...
Wondering how the C++ ecosystem is doing in 2023?
C++20 is the base dialect.
Python is the number one companion to C++.
The C++ toolset has remained stable in recent years.
Clang-based tools are growing in adoption.
Discover more JetBrains Developer Ecosystem results: jb.gg/deveco_cpp23
Use `CppWeeklyCLion` to get 25% OFF when you purchase a new CLion subscription or renew your existing one.
Episode details: github.com/lefticus/cpp_weekl...
T-SHIRTS AVAILABLE!
► The best C++ T-Shirts anywhere! my-store-d16a2f.creator-sprin...
WANT MORE JASON?
► My Training Classes: emptycrate.com/training.html
► Follow me on twitter: / lefticus
SUPPORT THE CHANNEL
► Patreon: / lefticus
► Github Sponsors: github.com/sponsors/lefticus
► Paypal Donation: www.paypal.com/donate/?hosted...
GET INVOLVED
► Video Idea List: github.com/lefticus/cpp_weekl...
JASON'S BOOKS
► C++23 Best Practices
Leanpub Ebook: leanpub.com/cpp23_best_practi...
► C++ Best Practices
Amazon Paperback: amzn.to/3wpAU3Z
Leanpub Ebook: leanpub.com/cppbestpractices
JASON'S PUZZLE BOOKS
► Object Lifetime Puzzlers Book 1
Amazon Paperback: amzn.to/3g6Ervj
Leanpub Ebook: leanpub.com/objectlifetimepuz...
► Object Lifetime Puzzlers Book 2
Amazon Paperback: amzn.to/3whdUDU
Leanpub Ebook: leanpub.com/objectlifetimepuz...
► Object Lifetime Puzzlers Book 3
Leanpub Ebook: leanpub.com/objectlifetimepuz...
► Copy and Reference Puzzlers Book 1
Amazon Paperback: amzn.to/3g7ZVb9
Leanpub Ebook: leanpub.com/copyandreferencep...
► Copy and Reference Puzzlers Book 2
Amazon Paperback: amzn.to/3X1LOIx
Leanpub Ebook: leanpub.com/copyandreferencep...
► Copy and Reference Puzzlers Book 3
Leanpub Ebook: leanpub.com/copyandreferencep...
► OpCode Puzzlers Book 1
Amazon Paperback: amzn.to/3KCNJg6
Leanpub Ebook: leanpub.com/opcodepuzzlers_book1
RECOMMENDED BOOKS
► Bjarne Stroustrup's A Tour of C++ (now with C++20/23!): amzn.to/3X4Wypr
AWESOME PROJECTS
► The C++ Starter Project - Gets you started with Best Practices Quickly - github.com/cpp-best-practices...
► C++ Best Practices Forkable Coding Standards - github.com/cpp-best-practices...
O'Reilly VIDEOS
► Inheritance and Polymorphism in C++ - www.oreilly.com/library/view/...
► Learning C++ Best Practices - www.oreilly.com/library/view/... - Наука та технологія
Wow _ for real? I was fully expecting std::placeholder or some shit like that.
_ is sugar for template constexpr inline std::variable_binding_placeholder
Best comment
yup hahah I was expecting the 100% same
Would have probably been std::ignore instead of std::placeholder, since std::ignore is how you did placeholders with std::tie before tuple destructuring was introduced. I really hope std::ignore can actually just be replaced with _ now in code that uses std::tie
Edit: to add to this std::placeholder::_n is a really cool feature of std::bind that allows you to basically reorder function arguments as you like.
This is very useful for locks, and other RAII wrappers of similar nature where the actual value is not as important as the object lifetime
According to the paper, a declaration of _ also gets an implicit [[maybe_unused]] attribute, making `auto _ = foo();` a new, probably better way to write `static_cast(foo());` for explicitly discarding a function return value (and suppressing any related warnings).
Obligatory to mention that this is the same approach Rust takes, where `let _ = foo();` explicitly silences warnings when ignoring the return value of a `#[must_use]` function.
`auto _ = foo();` and `static_cast(foo());` have different effect on the lifetime of the object returned by `foo()`.
I am really glad it is only allowed for the _ underscore and not all variable names, got spooked there for a bit.
This has been something I've used a LOT in other languages so it's great that we'll finally get a real placeholder in c++ soon™️
I wish they can deliver the final version of the reflection library for C++26
According to herb Sutter's summary of the last meeting that seems to be the plan right now but they haven't 100% finalized it just yet, same with SIMD and contracts.
Basically unless anything guess wrong it will be in C++26, but they don't want to make any guarantees just yet
great news, thanks@@sinom
I think it's quite 'poggers' I dare say!
I can't wait to use this in 2032!
Time to figure out how this interacts with the wildcard variable in the trompeloeil mock object library. I have learned things don't usually go well by default.
It's a cool feature. Makes me think there should be a lot of use cases of '_' that should produce a warning or error but perhaps they would get in the way of legitimate uses. And the C++ philosophy is that erroneous uses of a feature should be allowed as long as they would only be created on purpose and would be very unlikely to be encountered by a C++ newbie.
How about a way to use this as a placeholder in a function call for “out” arguments (by refs or by ptr) whose values I don’t care about preserving or accessing after the function returns? This would allow for much cleaner code by avoiding the need to explicitly declare new local variables just to pass them to a function and then do nothing else with them.
Interesting that you can use "-std=c++26". I expected something like "c++2c" instead.
Standard now have stable release dates, no more `c++0x` that grow to `c++11` (10y from prev standard). But side effects is if some thing is not ready, it will be cut-out from next release (that already happens couple of times like `c++14` that miss couple features that was planed for it).
@@von_nobody GCC allows `-std=c++2c` as an alias for `-std=c++26`, but Clang requires the lettered version, and will until after the final draft is published if the way they handled C++23 was any indication. (Clang 17 and under require `-std=c++2b`)
Hey, this makes this possible now:
#include
template
struct Deferer
{
~Deferer()
{
T t;
t();
}
};
#define defer(code) auto _ = Deferer()
int add(int a, int b)
{
return a + b;
}
int main()
{
defer(std::cout
you probably want defer macro to take ..., not defer (code)
#define defer(...) auto _ = Deferer()
otherwise everything after first non parenthesized comma is cut off
example defer(std::cout
@@BSOD.Enjoyer probably, I don't really write a lot of macros
We need reflection! )))) We'll write the rest ourselves))
Can you elaborate on this? I fail to see the link between static reflection and a placeholder name.
@@AnthonyDentinger The Placeholder is good, but it's not as necessary as other things in the core of the language. Which cannot be implemented by writing libraries without third-party code generation utilities.
@@DART2WADER This isn't how the standards commitee works. You don't not get reflection because something else gets in. There are multiple groups working on different things. It's not a single thread operation.
So it's shadow declarations as a feature. Neat.
Can you please make a Video on the use-cases of C++26 hazard_pointer and why not to just use a shared_ptr? Thanks.
Using Hazard pointers instead of std::atomic can leads to significant performance increase as usage of hazard pointers require mostly wait-free instructions that makes it's performance agnostic to number of readers so it scale perfectly with scenario involving many readers but few writers.
Hazard Pointers tend to be hard to use (it's basically a garbage collection scheme) so there's that trade-off.
@@aniketbisht2823 Is the performance difference really this massive to considee using that over the other?
@@peessinitro1395 If you are sure that your algorithm/(process using this DS) is not gonna use more than, lets say 8 threads, then I guess it would be fine, but parallel code is seldom written with that mindset. You expect your parallel algorithm to scale perfectly from N=1 to N=128 or more.
Ref-counting can kill the performance of std::atomic even if multiple threads just read it (access it) frequently and it's not modified, whereas schemes like Hazard pointer and RCU (Read-Copy-Update) are reader agnostic when it comes to scalability.
You should watch Fedor Pikus's talk on RCU. He goes in depth about the implementation and shows benchmarks. You need to be familiar with atomics and C++ memory model to understand the implementation.
I have taken inspiration from RCU/Harzard-Pointers and now I am working on my own data-structure for deferred reclamation which is even more constrained and hence simpler to implement and more performant (I hope).
I have a site for everyone to add their topic requests so I don't lose them in the comments - feel free to add your ideas and vote on other's ideas here: github.com/lefticus/cpp_weekly/issues/
Just like ~ in Matlab :)
At the end you say it "hides" the previous declaration, but it doesn't, right? As as soon as you try to use it after the second declaration, you get the ambiguous declaration error. So it's not hidden, as in replaced: it's still there.
I think in the proposal it's supposed to just allow you to use the first declaration as if it was an actual variable, and those that come after are shadowed instead. I think Jason has -Werror enabled
@@basilefff No. If there are more than one _ variables in the same scope the program will be ill formed. But if you introduced another scope and declare a single _ in that scope that shadows _ of the outer scope then you can use it.
@@aniketbisht2823 Oh, my bad, was reading old version of the paper.
This time the avatar is sucking his index finger 😂 How can I unsee this? 😅
What about using that in classes and the -Wshadow warning?
I like it
Is this like function overloading... but with variables?
Finally! Of course, C++ always has its own quirks, but it is still a valuable feature
Doing it this way is nice because it preserves backwards compatibility with source that might have used _ as a variable name.
@@aDifferentJTWould still be nice if there was a warning that catches this
Isn't std::ignore supposed to be used when you don't care about the variable?
I really have a hard time thinking of this is a good thing, let's think of the concequences on junior developers a minute. Isn't it a open door to even more criptict error messages?
What is the impact on compilation time?
I think it's not that complicated a feature for anyone to use. Also, why would compilation time be affected much or at all? I am not sure about cryptic error messages, that actually may be a problem
This feature will end the frustration of inventing names for objects of `std::lock_guard` and similar RAII types.
I really think it's only potentially useful in the case of structured bindings
This. This so much.
Are there any books on c++26 yet?
Not quite yet, no.
This is good news, but I actually thought they had already added this in a prior version and waiting until 26 is annoying.
They got that from python
I thought you could already use std::ignore to ignore values that you weren't interested in?
std::ignore is designed to work with std::tie(), where you are assigning already-declared values. It doesn't work with structured bindings or variable declarations.
@@_noisecodeGood to know, thanks. It sounds like I've been using it wrong then... I've used it in a couple of places when I've wanted to discard the result from a [[nodiscard]] function (Where the function should never have been NoDiscard, in my opinion.).
@@BenUK1 Er yeah, that's definitely a valid use case too actually! The original std::ignore motivation was indeed to help with std::tie, but you're right, it does also provide a nice clean alternative to static_cast() for discarding [[nodiscard]] return values at the top level. It still doesn't play nicely with structured bindings though.
Yet another convenience feature that will add a whole bunch of extra rules to the language.
We are already wading through too many new rules and exceptions to rules.
It would be so much better if the compiler had a way to ensure "_" is never used and force a name when it is. This makes "_" a new half-blood magic construct.
Unfortunately, they can't do that because that would break backwards compatibility.
I could see deprecating and eventually removing actually using "_", but at least initially, it wouldn't be good to break existing code that might use it.
I wouldn't be surprised if there's a new clang-tidy warning soon to detect uses of variables named `_`
@@yato3335 Could've added a warning for it at least, though
I get that this is useful - but IMHO using an "_" variable should be an error in the language. Why would you want to declare something as "unused" by using the special "_" var and then later use it in your code?
For backward compatibility of codes that use the variable _ normally. Now that this is a feature, you really shouldn't use it.
How about usage of the macro define _(str) gettext(str)?
will it work with any name?
int a = 5;
int a = 6;
no
@@eLBehmo wait, just for underscore??? really??? what makes underscore special?
@@nmmm2000 It seems like it's mostly for backwards compatibility, so all old code still behaves the same way, but since they want to have _ be a special placeholder, they do it as a special identifier that can be shadowed.
That's the most C++ way solution imaginable. Instead of being a new syntactical construct it's now a magic identifier you can sometimes maybe use. Instead of being a discard pattern like in Rust
Most languages do it this way, see Rust and Python for example
well, kinda what you have to do when you don't want to break existing code
I don't know why people just randomly use _ as an identifier, but some do, not for discarding it too.
@@kuhluhOGmaybe they at first used this as a discard patter but suddenly needed this value, so they used it and were too lazy to rename it. And while this is a shitty thing to do, I can totally see this happening
Unfortunately a number of libraries use _ as an identifier for something other than a `std::ignore` equivalent so this was the best they could do without using double underscores as the discard pattern.
@@TheClonerx Rust does not do it this way. It's not an identifier.
Получается, не std::ignore
Naming is hard so now you don't have to!
use dot
Bugs are coming in 2026
I wish that the values would be destroyed when you redeclare the underscore variables. It would allow for rust-like drop semantics.
Rust doesn't drop objects held by variables when those variables are redeclared, they live till the end of the scope like normal.
@@vytah is that so? What if the name redeclares the variable for the remainder of the function body? I thought that rust drops objects as soon as they become unreachable.
@@yato3335 Not being nameable doesn't mean unreachable. There might be other ways to reach the first object, e.g. via a reference created between the two objects, or the first object might be used by the second object. Unless the first object is destroyed first by moving from it (with for example std::drop), they are dropped in the reverse declaration order, like in C++.
@@vytah makes sense, didn't think about it
_, println... So, C++ tries to become Rust...
I remember println from way back in pascal era. and _ thingy is used as long as programming languages existed. rust has nothing to do with those
Does this mean that warnings for unused variables are put back in for C++26, or is this another feature copied from Rust on such a surface level that it doesn't bringing the real benefits?
I could see it possibly being added back in for unused portions of a structured binding, specifically, but that will be a compiler implementation detail.
It's a shame that I have to wait a couple of years for a feature to be implemented into the language, and then a couple of years for the C++ standard to make it into the C++ project itself.
by which time ChatGPT will be doing your job anyway...
Very interesting to see that my proposal that never made it into a meeting, has been implemented ;)
github.com/janwilmans/janwilmans.github.io/blob/master/auto.md
I imagine this change will break a lot of code
If so, its deserved. Well actually, probably not. Usage of _ is probably only ambiguous if there are more than one _. Up until now, just 1 _ may exist per scope. Therefore, if used only once, _ may be a valid variable name, if used more than once it is the anonymous _.
@@DerAlbi i use it mainly for lock guards or temporary intermidiate values, but it seems it's scoped, so shouldn't be a big problem
Can you give a simple example.of code that it will break?
@@peterfordham3562 not really. as long as it it's scoped it should be fine. any code that uses multiple _ in the same scope is already broken.
How so? It's currently a compiler error to declare two variables with the same name in the same scope. This change accepts strictly more sources.
Why would anyone want to do something like this?
I really hate this language :)