I love how over the past decade my own C++ utility library has been continuously shrinking because with each update there are more and more utility functions (like the to_underlying this article mentions) and even complete libraries (like ) which replace self-written or 3rd party code.
I always worry as much as anyone else on each new release for the additional complexity ("the committee is out of control!!!!1!!eleven!"), but on each compiler upgrade when I actually get to use the new versions of the standard I'm always pleasantly surprised about all the little low-key quality of life improvements.
Three new utility functions in C++23
31–40 of 196 posts
Re: Three new utility functions in C++23
#32Hmm. How often do people actaully want to std::byteswap as opposed to "convert this value from native byte order to big-endian" or "convert this value from little-endian to native byte order"? i.e., the functions documented in https://man7.org/linux/man-pages/man3/endian.3.html (why oh why are they not also documented in the GNU C Library Manual...)
Yeah, for portable code you also need a function to tell you if you're on an architecture where you need to do a byteswap for the data you have. e.g. you know you have data in little-endian format - do you need to swap it to work with it natively? That depends. Maybe having something like convert_be() and convert_le(), one of which is a no-op and the other does the byteswap (depending on your arch) would be better. I…
For instance... /usr/include/x86_64-linux-gnu/bits/endian.h has:
#define __LITTLE_ENDIAN 1234 #define __BIG_ENDIAN 4321 #define __PDP_ENDIAN 3412
Apparently this is called 'middle-endian'... yikes!
On the other hand I sort of like having one function that's clearly used for importing values to the host's byte order, and another for exporting values from the host's byte order. But maybe that's just because I'm used to having them...
Re: Three new utility functions in C++23
#33I understand why it's there, but I do find it fun that when many people are trying to reduce undefined behaviour in their code, std::unreachable is literally defined as "this is undefined behaviour, use that to optimise". I suspect 99.9% of uses of std::unreachable would be better replaced by abort. (There will be those times when the code is correct and the optimisation gains are worth it -- but they will be rare).
Re: Three new utility functions in C++23
#34Why is it called "byteswap" and not "bytereverse"? "Swapping" can be done in any number of ways, but only one way to reverse.
The Arm architecture does call this operation "reverse bytes", though, so it's not universal to call it "swap".
Re: Three new utility functions in C++23
#35Earlier quoted context omitted.
+100 I felt physically ill when I read: It’s intended to be used when you know you have an execution path in your code that cannot be reached but the compiler cannot figure that out. It felt like saying to the compiler, "please, find a way to make my program break even more easily". Exactly not what I need.
If a code path that's supposed to be unreachable is reached then the program is already broken. Unless it has a bug, a compiler will not make a program more broken. At worst (or best, depending on how you look at it) it will only make any bugs it already has more obvious.
An abort would make them obvious, surely unreachable makes them less obvious?
Re: Three new utility functions in C++23
#361.) Coming from embedded programming, I can see the utility of `std::unreachable`. But shouldn't this be a compiler directive? Or a standardized #pragma? Can someone more knowledgeable in C++ say whether using functions as markers is a common mechanism in std:: ?
2.)Maybe the example is bad here, as it doesn't even save typing. (18 chars for `std::to_underlying` vs. 16 for `static_cast`. The 'old' variant seems more expressive to boot. If anything, how about `static_cast`? or ...
3.) The usefulness of `std::byteswap` to convert data to network byte order seems trivial vs. the venerable old `htonl` family of functions. `std::byteswap` seems more like intrinsics meant to expose possibly present target machine instructions to the user. Like `std::unreachable` this is probably of most use to embedded / low-level programming. This may be a deficiency in the article...
If it's not obvious, I'm not a big C++ fan and read the article with C-tinted glasses :)
Re: Three new utility functions in C++23
#37>Network protocols specify big endian for the order of transmission Only in the parts specified by the protocol (headers etc). I encourage everyone sending data over network in a novel way to just use little-endian.
That's not a good advice. Only if the sender and receiver are guaranteed to be running on little endian architecture you can make such a claim. A better advice is to always consider the endian-ness when designing protocols and have a strategy to handle it.
Re: Three new utility functions in C++23
#38Earlier quoted context omitted.
It's undefined behavior. The compiler is free to do whatever, including making your program more broken.
If you have undefined behavior, your program is already broken. No such thing as "more broken"; there's already no theoretical limit to what might happen if it gets triggered.
Compare these two blocks similar to the article
switch (ch) {
case 'a': do_a(); return;
case 'd': do_d(); return;
// ch is guaranteed to be 'a' or 'd' by previous code.
default: assert(0);
}
switch (ch) {
case 'a': do_a(); return;
case 'd': do_d(); return;
default: std::unreachable();
}
If the programmer is wrong about `ch` in the first one, the program terminates.
For the second one, the compiler could change it to be equivalent to if (ch == 'a') { do_a(); }
else { do_d(); }
return;
If the programmer is wrong here, the program might `do_d()` with unintended consequences. I'd say "going down unintended codepaths" is typically considered worse than crashing.N.b. fixed last code example- thanks afiori.
Re: Three new utility functions in C++23
#39Earlier quoted context omitted.
If a code path that's supposed to be unreachable is reached then the program is already broken. Unless it has a bug, a compiler will not make a program more broken. At worst (or best, depending on how you look at it) it will only make any bugs it already has more obvious.
> At worst (or best, depending on how you look at it) it will only make any bugs it already has more obvious. An abort would make them obvious, surely unreachable makes them less obvious?
Re: Three new utility functions in C++23
#40Earlier quoted context omitted.
If you have undefined behavior, your program is already broken. No such thing as "more broken"; there's already no theoretical limit to what might happen if it gets triggered.
Undefined behavior is considered worse than crashing, which is typically the alternative when reaching "unreachable" codepaths. Compare these two blocks similar to the article switch (ch) { case 'a': do_a(); return; case 'd': do_d(); return; // ch is guaranteed to be 'a' or 'd' by previous code. default: assert(0); } switch (ch) { case 'a': do_a(); return; case 'd': do_d(); return; default: std::unreachable(); } If t…