Things C++26 define_static_array can't do
Comments
Pesthuf
stodor89
> I love how to do anything in this language, you have to fight it with all you have. You have to use features in ways that feel like they were probably never intended to be used in. Everything is just an accident, some random pattern randomly discovered by someone when some typo happened to compile.
This but unironically.
wewtyflakes
This is so on-brand for C++, whether that is a blessing or curse is left up to the reader.
randusername
> Think of constexpr evaluation as taking place "in the compiler’s imagination."
This is a great line.
constexpr and std::execution seem like neat ideas, maybe I'll give them a shot if I build an AI harness around the compiler so it doesn't make me feel like a hopeless idiot for trying new things.
Doxin
I'd recommend you'd give D a try. It manages to have a bunch of the cool features C++ has, while still largely feeling like working in C with some of the cruft fixed.
D's equivalent to "constexpr" is "compile time function evaluation". i.e. in any context where it only makes sense to run code at compile time, it will do so. This makes it trivial to do some pretty complex things at compile time. I put together an example that shows creating static arrays, dynamic arrays, and a dynamic array with a partial fibbonaci sequence all at compile time[0].
[0] https://gist.github.com/SuperDoxin/d9fcc68b73c035cbde7f0bd08...
tialaramex
The problem isn't so much that you feel like an idiot, at least at the time, but that you may think you're a genius and yet actually what you wrote was nonsense and the C++ compiler was under no obligation to tell you about that, indeed in many cases it's forbidden from doing so.
The standard does require that if work was done at compile time the compiler is supposed to tell you if that was nonsense but (a) actually C++ is so complicated your compiler likely has many bugs in this respect and (b) you probably aren't sure the compiler did the work you expected at compile time, knowing all the excuses requires considerable expertise.
ghm2180
To be clear we are — in the service of speed — trying to bake data into compiled program output binaries, which is ostensibly faster because code-pages in memory when executed by CPU as instructions already have it?
Maxatar
No you are baking data into the compiled program so that you can perform compile time operations on that data. These compile time operations are most often used to guard against erroneous runtime behaviors.
If all you want to do is bake data into a compiled program, there is the #embed feature added to C++26.
TuxSH
The point of the article and of define_static_array is to convert stuff like constexpr std::vector to constexpr std::array.
New (and delete) can be used in constexpr functions, however memory "allocated" like that cannot leave the constexpr "sandbox" so to speak, therefore std::vector cannot be generated at compile-time, but std::array may.
If you are working with fixed-size data like LUTs, just use std::array [1]
[1] Make sure not to use std::to_array when embedding 200KB+ files, as it's a mere constexpr function and not a language construct and will exceed constexpr limits; either specify the size or use a C-style array in this case
ok123456
Would the PMR variants of the STL datatypes be a solution here? The compiler could fill in the details of the range in question (the ro section), and give you constexprness?
Maxatar
No, compile time memory is not the same as static storage duration/ro section.
oseityphelysiol
C++ people are great at making problems for themselves and then solving them to no end.
This does not look like a productive way to get things done.
SuperV1234
C++ critics are great at analyzing niche corner cases of the language and generalising those to the entirety of its feature set.
This does not look like a productive way to get things done.
imtringued
It's way less productive to spend significant time on criticizing something you don't use. Better spend that type on niche corner cases than be busy with the entire language.
kevin_thibedeau
C arrays are better than this mess. All the problems caused by the intervening generic programming abstraction machinery disappear.
compiler-guy
The nice thing about C++ is that if you want to use plain old C arrays, you can. And there will be no extra overhead over plain C.
You will lose many nice features like fancy strings and easy array resizing (which may or may not be acceptable to you), but you don’t have to pay for it if you don’t use it. (Mostly)
This does seem pretty complicated. And I doubt I will ever use it. But for some the trade off is worth it, and they get to make the choice.
SuperV1234
Didn't know you could use C arrays to get static compile time reflection, guess C was really ahead of its time!
kevin_thibedeau
Wrap them in a class with a consteval constructor.
gkedzierski
What language do you consider to be productive, in comparison?
htobc
Rather than engage in an unrelated language-war flame bait, why not actually discuss this particular issue with C++? Yes having a language built around zero cost abstractions for low level programming is a must, but how does that end up justifying this wild complexity around making constexpr more powerful?
In the real world I would think trying to do any of the things discussed in this article should be an automatic commit rejection on any project.
SuperV1234
This particular issue is a niche corner case of C++26 reflection, which -- like reflection in other languages -- is a massively useful feature.
In the real world, failing to understand what you're reading and eagerly generalising to the entire language should be an automatic hiring rejection in any team.
ux266478
i'd like to point out that C++26's reflection is the third reflection standard defined by the language to cover the "niche corner cases" that have hereto been lacking from the other two (RTTI and type traits). this specific "niche corner case" also would not exist if C++ did not commit to a poorly-bolted on feature that turned out to be accidentally powerful, and instead intentionally designed powerful metaprogramming facilities from day 1.
there's a point at which "pragmatism" starts being anything but, and it was around C++11 give or take a standard. how on earth do you use it day to day and not feel the schizophrenic non-design being a generalized property across the whole language?
htobc
Hey buddy, maybe not liking something is not the same thing as not understanding it? Maybe saying, "this specific feature is bad" is not a generalization to the entire language? Maybe niche corner cases are evidence of poorly chosen primitives and bad design? Maybe jumping straight to smarm and skipping past actually defending the feature means you probably create a work environment no one wants to be in? And an esoteric paradigm like "constexpr two-stepping" that is explained in the article by linking a video that is _over an hour long_ is a perfect example of something that, while perhaps the author and demonstrator explored more for fun instead of as a serious thing to do, would only ever be put into a production code base by the most amateur of architecture astronauts, shortly before their startup fails?
For real though, defend constexpr two-stepping as a real use case for serious people.
Or did you just get a little bit confused and think the criticism here is actually coming from people who are out of their depth from hearing "compile time optimization" or don't know what reflection is?
SuperV1234
> would only ever be put into a production code base by the most amateur of architecture astronauts, shortly before their startup fails?
Yep, definitely failure of understanding. :)
> For real though, defend constexpr two-stepping as a real use case for serious people.
Of course, here's a use case: I am a serious person developing a library that provides a nice API to solve a real-world problem using C++26 reflection. As part of the internal library machinery, I need some temporary storage for some compile-time algorithm (e.g. building a graph for automatic parallelization, or some other thing like that). In an internal helper function of my library, I use constexpr two-stepping to solve the problem without imposing hard limits on my algorithms and keeping the final API as simple as possible for the end user.
Then I submit my PR, but htobc reviews it and immediately rejects it, ignoring the real business value of the library because I made a conscious engineering decision to use a niche technique to solve a language limitation as part of my library implementation.
Then my startup fails.
htobc
And then it turns out after ignoring any attempts to actually engage in the technical merits of how constexpr is done in C++, you made it 25 minutes into the 1 hour video, past all the obvious jokes from the presenter about how absurd it is to try and use the feature, where it turned out that it wasn't supported in your tool chain. Then you realized you were weirdly obsessed with making sure no one ever criticises anything about C++ and it turned out your real special interest was not having friends.
(There are far simpler ways to do that.)
SuperV1234
Many, if not most, useful libraries, languages, and tools have weird hacks and corner cases in them that look esoteric and insane from the outside.
The reasonable engineer understands why they exist. The engineer with a hate boner or negative bias for a particular technology jumps on the opportunity to make a generalized statement.
I'd rather not be friends with the second kind of engineer. :)
htobc
Okay so why not _discuss that_. You're N posts deep in a thread where I've been actively trying since the start to pull this away from a language flame-war, (and acknowledge your bizarrely anti social style of interaction) while again pulling the conversation back towards actually being about constexpr, and all you can say is anyone who criticises it is too stupid to understand it.
I think it's telling that you are quick to respond to my superficial meta discussion, but have left the one reply up the chain about this being the "third reflection standard from the C++ committee" conspicuously unaddressed. Gotta dodge saying anything real at all costs? Or just trying to get your rocks off with an internet fight?
SuperV1234
It's quite simple: statements such as "In the real world I would think trying to do any of the things discussed in this article should be an automatic commit rejection on any project." really piss me off.
I find it ironic that you try to "avoid a language flame-war" by implying that anyone writing code like the one in the article, no matter how niche the reason/situation, is a moron.
htobc
I have tried to make it clear in my posts that I like and use C++. This is not a language flame war, it's criticism of a feature's implementation.
I did not say anyone using this is a moron, I said I believed a commit exercising the niche edge cases demonstrated in the article should be rejected. In fact, had you asked, (instead of jumping to saying I was too stupid to understand what I was reading) I would have said you need to be very smart to write code like the examples in the article, and that's the reason I would reject it.
Sure it's fine and even fun to exercise these relatively recently released features and really explore the niche edge cases in a personal project, but they are a future maintenance headache in team based software development. The kind of compile errors walked through in the video are simply not where I would want my team spending effort debugging on any given day of the week.
Metaprogramming was not invented in 2020. There are a dozen different ways to get those optimizations in front of the compiler. They might not be as theoretically pure, or might not be using first order features of the language, or might have to sacrifice parts of the static analysis flow, but the trade offs are more than worth it when it comes to delivering.
SuperV1234
You shouldn't use what's demonstrated in the article in a random commit in the middle of business logic.
But even in a real-world project, using this technique might have value as part of an internal implementation detail of a useful component that leverages C++26 reflection.
"trying to do any of the things discussed in this article should be an automatic commit rejection on any project" is a very strong statement that suggests you won't even care about the particular situation. It implies that, as soon as you see something that you deem overly weird, you immediately reject it without considering why it is weird and if that weirdness is needed to achieve a valuable goal.
Even in a mature and robust project there is room for esoteric techniques if well justified, commented out, and weighed against alternatives.
To give you a realistic example: you can reflect on struct data member names even if C++20 if you parse __PRETTY_FUNCTION__ at compile time. This is what Boost.PFR, Lahzam, and my own MiniPFR libraries do.
It's what a common developer would refer as "disgusting", "weird", and what would prompt the average C++ hater to take the opportunity to bash the language and remind the world how they think that the Standards Committee is a bunch of incompetent people. Not saying this is what you think, but you see where I'm coming from.
If people had applied blank statements like yours and decided that any code parsing __PRETTY_FUNCTION__ at compile time "should be an automatic commit rejection on any project", we wouldn't have a genuinely useful feature that allows us to reflect data member names in C++20, six years prior to having official reflection.
Yes, it's an esoteric technique. It's a hack, a workaround for a language limitation or language design failure. It's "experts-only" or whatever. Exactly the same way you feel about what the article demonstrates.
Yet, there was a good use case for it -- a very useful and valid one.
Outright banning certain techniques because you cannot understand how they could be valuable in very specific scenarios is honestly infuriating. Obviously, the use of niche/dangerous workarounds should not be liberally promoted. At the same time, automatically rejecting any commit is an insult to the intelligence of the person who wrote that code: perhaps they had a good reason to write it that way.
Dylan16807
> Outright banning certain techniques because you cannot understand how they could be valuable in very specific scenarios is honestly infuriating. Obviously, the use of niche/dangerous workarounds should not be liberally promoted. At the same time, automatically rejecting any commit is an insult to the intelligence of the person who wrote that code: perhaps they had a good reason to write it that way.
The problem with this discussion is that you pulled "because you cannot understand how they could be valuable" out of nowhere. They're talking about rejecting it despite the value. You should not be infuriated for that reason.
If there's an insult based on intelligence, it's saying they're too smart and need to write something dumber so that more people can maintain it.
OneDeuxTriSeiGo
[dead]
Grognardicle
He's half-excommunicated.
LLVM and many conferences want nothing to do with him. gcc and the ISO standards committee still invite him to contribute, although not in a leadership role.
O'Dwyer is a remote consultant on C++. It's like the ideal role for a sex offender since it doesn't require him to go outside or put him in a room alone with others.
I don't think he's ever been accused of rape, sexual abuse, or even harassment since being released from jail. This is remarkable given the ISO C++ committee meetings have a reputation for being drunk, unsafe, and harassing women. Many other members have been credibly accused of harassment.
It's easy to say "remote work is a great idea for sex offenders" but difficult to say "in my profession".
OneDeuxTriSeiGo
That's a fair point.
WalterBright
Let's try this:
constexpr std::vector<int> f() { return {1,2,3}; }
constinit std::vector<int> p = f(); // error
in D! const(int)[] f() { return [1,2,3]; }
immutable int[] aaa = f();
And the object file, look ma, aaa[] is statically allocated: internal:
db 001h,000h,000h,000h,002h,000h,000h,000h ;........
db 003h,000h,000h,000h,000h,000h,000h,000h ;........
__D5test63aaayAi:
db 003h,000h,000h,000h,000h,000h,000h,000h ;........
db 000h,000h,000h,000h,000h,000h,000h,000h ;........tialaramex
But why though? What is the purpose of the immutable "dynamic" array in your D?
We're unavoidably going to learn at compile time how big the array is, and knowing how big it is will always be the same or better, so we should always do that.
WalterBright
If you know at compile time what the size should be:
int[f().length] array;
should do it.
I love how to do anything in this language, you have to fight it with all you have. You have to use features in ways that feel like they were probably never intended to be used in. Everything is just an accident, some random pattern randomly discovered by someone when some typo happened to compile.