This solves a problem Ive been having for quite a while as well but looking at it still hurts my soul
@xplorethings2 жыл бұрын
This is what people mean when they say template metaprogramming is dumb. It's like Rube-Goldberg software development, you're trying to do something conceptually so simple, but jump through insane hoops to get there.
@warlockd2 жыл бұрын
I kind of like the poison pill approach they went with on consteval. Now lets see if gcc will properly tell you what line that consteval is on:P
@chudchadanstud9 ай бұрын
No it's just a poor implementation of it. It's fine in Rust. I don't know why the foundation is rushing features.
@meowsqueak2 жыл бұрын
Well done solving this puzzle, but I’m left in shock. The need to employ a template, static constexpr variables, a lambda function, and four utility functions just to compile-time generate a static string in C++ is an embarrassment. What decisions brought us to this point? How will we explain ourselves to our children?
@warlockd2 жыл бұрын
That constexpr is spellt conteval. Good lord this is grinding my gears. Ten years ago I thought constexpr would fix this but we had to invent ANOTHER const statment because the word "may" screws with people. I can accept constinit, even argue that we should have it in the C20 standard. But ugh this makes my head hurt.
@benjaminnavarro8652 жыл бұрын
IIRC the committee didn't have time to find/evaluate a solution to make dynamically allocated memory inside a constexpr context available at run time before C++20 has to be shipped. I don't know why this wasn't fixed in C++23 though, but maybe again by lack of time because of the pandemic.
@warlockd2 жыл бұрын
@@benjaminnavarro865 But I thought something put on the heap automatically doesn't make it runtime? Right now compilers just either? Or is this in regards to pointer arguments?
@cppweekly2 жыл бұрын
Yes, there was a proposal to move a compile-time dynamic allocation into static memory automatically, but it didn't get through.
@benjaminnavarro8652 жыл бұрын
@@cppweekly Do you know why? Or at least have the paper number, I'm curious to know if the proposal wasn't technically sound or if the committee is waiting on a revision or something for it to happen
@andreanobile2 жыл бұрын
Only elite programmers working in the language full time for their entire life are able to use it. 5y for a string. This leads to madness
@a3142 жыл бұрын
OMG! You can do this in D in 2 lines. For sure C++ is creating jobs! import std.range: repeat, join; pragma(msg, "hello world, ".repeat(3).join);
@ohwow20742 жыл бұрын
C++, a language that has complicated solutions for trivial problems. Enjoy!
@vanjazed70212 жыл бұрын
Is that D statement executed at compile time?
@a3142 жыл бұрын
@@vanjazed7021 yes, indeed
@willofirony2 жыл бұрын
Now, forgive me, dementia has been knocking at my door for some time, now. My understanding went like this: Consts are important because they eliminate the use of 'magic numbers' while retaining the immutability of literals. Constexpr goes one better by showing our work that came up with that immutable value. That obviously is erroneous, something like 80% of this channel wouldn't be about constexpr, if it were correct. Will somebody kindly give me a hint were I turned two pages at the same time? I am afraid by 20 minutes into the video, I started hearing my irascible professor complaining about over egging the pudding. I am grateful for the challenge though.
@warlockd2 жыл бұрын
Its because some idiot said a constexpr "may" be compile time. Not "should" or "will be" that it "might". Because of that the compiler can/will dance around your code till your pc locks up with a 2 terabyte dump file or, aka, the looping constexpr lamba. The consteval is supposed to be a poison pill that makes this all simpler (as shown in the video), However, to be honest, I am not sure what the output "should" be? If I make a program that tells the compiler to either make 10megs of data, or produce a file with 10megs of data, but don't use it, what should its output be?
@TheChemicalBassist2 жыл бұрын
Maybe I'm being a little masochistic, but I think this is a beautiful solution. Love that you were able to figure this out!
@N....2 жыл бұрын
Very nice! Hopefully these issues can be smoothed out in future standards
@meowsqueak2 жыл бұрын
“Nice”? You think this is nice? This is four non-obvious functions and a template to generate a static string. This is a complete travesty! Can’t anybody see that the emperor isn’t wearing anything?
@oof-software2 жыл бұрын
This is the stuff I am subscribed for! Thank you very much, this exact problem has annoyed me for quite some time and I really like this solution.
@acf2802 Жыл бұрын
"This is unteachable." - Bjarne Stroustrup
@troctschcpp52632 жыл бұрын
One more step toward C++ being able to apply Normal order evaluation (lazy evaluation), at least, at compile time! Great stuff, thank you Jason!
@IllumTheMessage2 жыл бұрын
Good stuff Jason. Looking forward to trying out the new library.
@cppweekly2 жыл бұрын
Still a WIP, but tested on every platform that allows it: github.com/lefticus/tools plus a conglomeration of other constexpr-related tools I've needed over the years.
@atilaneves762 жыл бұрын
Meanwhile, in D: import std.range : repeat, join; pragma(msg, "hello world, ".repeat(3).join); Yes, at compile-time.
@AndreaBarbadoro2 жыл бұрын
that's very good. I arrived at a similar solution while trying to do compile-time string formatting, but I didn't know the callable trick so my user code has to pass parameters as template values from the start. With this callable route, i think I can refactor my code to be nicer for the user
@cppweekly2 жыл бұрын
Check this out also: devblogs.microsoft.com/cppblog/how-we-used-cpp20-to-eliminate-an-entire-class-of-runtime-bugs/
@AndreaBarbadoro2 жыл бұрын
@@cppweekly very interesting. Also very cool use of std::type_identity
@Nobody17072 жыл бұрын
The NTTP as a conxtexpr static variable trick still blows my mind.
@Tyranisaur2 жыл бұрын
I want to be pedantic about it, so I'll point out that the array was originally 10 megabytes, then it was changed to 10 mebibytes.
@DS1272 жыл бұрын
Yeah, no. OG Megabyte 4 lyfe.
@pcfreak19922 жыл бұрын
Thank you 🙏
@flamewingsonic2 жыл бұрын
I came here looking for this comment, and was not disappointed.
@treyquattro2 жыл бұрын
Orders of magnitudes of bytes should always be powers of 2 (thus making the invention of "mebi", "kibi", etc. obsolete). One megabyte == 1,408,576 bytes. Power to the pedants! ETA: This is also how we get screwed out of SSD storage, e.g.
@Quazgaa2 жыл бұрын
bro. its time to leave the basement
@n3141-d3s2 жыл бұрын
Cool! I think you could pass make_data as a template parameter to to_string_view instead of as a normal parameter. In this way, I think the compiler could probably do even less work at compile time (of course, at runtime, it is already minimal)
@cppweekly2 жыл бұрын
I was going to aesthetics with usability, but to your point, then it might be possible to pass a lambda with captures, since the captures would now be part of the NTTP.
@earlye2 жыл бұрын
A while back I wrote a library to replace boost::format (I'm pretty sure this was pre-std::format adoption), because I found that boost's parsing was slow enough to justify my choice through profiling for this application. The replacement used a preprocessor + template library I found online to make and process strings at compile time, and it converted a given string into a type that would directly convert the provided data without any runtime parsing of format specifiers. So you'd say something like hax::format("blah %d ") % value, and that would generate code that was basically std::puts("blah "); hax::put_signed_decimal_int(value); std::puts(" "); constexpr has come along so well that I suspect rewriting this library could actually be a fun challenge.
@puyadaravi31092 жыл бұрын
If the compiler is not going to create the 10MB array, why not make the array as big as std::string's max size so that we know it is big enough instead of some arbitrary size?
@cppweekly2 жыл бұрын
Turns out the size of the "big enough" array has a huge impact on MSVC compile times. So it's not quite as flexible as I thought.
@46414C43482 жыл бұрын
This kind of stuff makes me think C++ will be replaced by a better tool.
@tylovset2 жыл бұрын
Indeed, the idea of mixing compile time metaprogramming with conventional c++ data structures has too many implications. I'd rather see a clean compile time only mode/environment for this.
@Quazgaa2 жыл бұрын
c++ needs to be killed with fire and start all the way over from scratch
@DavidMayolaTorres2 жыл бұрын
That's crazy!
@Swedishnbkongu2 жыл бұрын
Also, why prefer lambda arguments over nontype template parameters? The inputs to both are always constexpr for this pattern. I often use template parameter list as a replacement for normal function parenthesized list when the parameter needs to be used/provided as constexpr
@JohnDoe43212 жыл бұрын
I can't decide if this is awesome or awful. 😁
@Quazgaa2 жыл бұрын
interesting video as always! im glad to see from other comments here though that im not the only one to say something like: a small piece of my soul died while watching this video. i know it feels awesome for the hero who figures out a hack like this, but can we also still acknowledge that overall this is awful, not awesome. that is to say, clearly there is a shortcoming in the language that should be addressed so that people can accomplish the things they set out to accomplish in a normal way.
@danielrhouck2 жыл бұрын
I’m at 4:10, and I’m not going to watch the rest right now. Because I think I can do it and want to give it a shot myself before seeing your solution.
@danielrhouck2 жыл бұрын
And I failed. I know things are happening at compile time but I can’t convince the compiler in all the places it matters. It’d work if the parameters of consteval functions were constexpr.
@Sebanisu2 жыл бұрын
Cool stuff! I'm guessing if your oversized array buffer too small it'll just give you a compile time error. Maybe could be a template argument. *shurgs*
@cppweekly2 жыл бұрын
Yes, it will result in a compile-time error. it *might* be possible to do a compile-time retry logic with if constexpr, but I'm not 100% sure about that.
@didgerihorn2 жыл бұрын
I tried to solve Advent of Code 2021 at compile time, and is was a mess (but in most cases, it worked). A library would have been super helpful. I think this December, I'll embrace CTRE (compile time regular expressions) and non-type template parameters. Thank you so much for pointing out these techniques!
@cppweekly2 жыл бұрын
Here's the library: github.com/lefticus/tools/blob/main/include/lefticus/tools/static_views.hpp There's more than just that header.
@didgerihorn2 жыл бұрын
@@cppweekly thank you very much, and the non promoting ints sound very promising, too!
@Ranoiaetep2 жыл бұрын
A slight improvement, you forgot about `std::copy_n` 😄
@cppweekly2 жыл бұрын
Hmm... I might have to review the code there.
2 жыл бұрын
I'll wait for the constexpr string.
@galier22 жыл бұрын
Laughing in D. import std.stdio; string rept(string s, int n){ string ret; for(int i=0;i
@warlockd2 жыл бұрын
Oh good lord. Because constexpr has the word "may" in it meant we get 10 years of this till consteval. Even if msvc dies when it try's to move a god damn pointer from the C++ domain to C, atleast it does consteval right in c++20.
@nivo63792 жыл бұрын
Looking forward to the library!
@cppweekly2 жыл бұрын
Here's the library: github.com/lefticus/tools/blob/main/include/lefticus/tools/static_views.hpp There's more than just that header.
@pcfreak19922 жыл бұрын
Can the hard-coded 10MiB be changed to a dynamic value based on the input string? Or would a bigger string at least fail compilation?
@cppweekly2 жыл бұрын
It will fail at compile time. I should probably make the limit into a compile-time template parameter.
@FastNotSave2 жыл бұрын
You can't make the size really dynamic, because then you would have to evaluate everything twice again. However, you could make the size a template parameter so you can provide the upper limit for each call individually. And if you happen to pass a string that's too big you'll get some sort of compiler error because std::copy would run into UB and UB is disallowed in a compile time context. Of course you could also just use an assertion or check the size yourself and throw an exception if the string is too big, the compiler will halt and tell you when it reaches a throw statement.
@DaveWhipp2 жыл бұрын
I'd imagine there's some SFINAE magic one could incant to fall back to doing the work twice (thrice?) if it overflows on the first attempt
@andrei-edward-popa2 жыл бұрын
You can take for example a std::vector from compile time to runtime world as std::array, but do you think it is possible right now to get a std::vector into an std::array?
@cppweekly2 жыл бұрын
This is definitely doable, but takes several steps. github.com/lefticus/tools/blob/main/test/static_views_tests.cpp#L138-L147 I have gotten some level of map -> static data working.
@andrei-edward-popa2 жыл бұрын
@@cppweekly Thanks, I will take a look over it.
@c0d3_m0nk3y2 жыл бұрын
Now imagine trying to understand this code without any comments in it ;)
@iamjadedhobo2 жыл бұрын
Use the URL to this video as a function name :)
@ohwow20742 жыл бұрын
@@iamjadedhobo If one day YT goes down then that URL won't work. And the humanity will go extinct if this code plays a huge role in a serious project lol.
@TrueWodzu2 жыл бұрын
I don't understand this video with comments included O_o
@myrefone83672 жыл бұрын
That's great thanks. I already need this. I also need the string type to be any string-like type and the string view type to be any string_view-like type. Count me in if you wanted to make this a library. I'm gonna be using it in my own framework anyway 😅. Thanks. It's a combination of great techniques.
@cppweekly2 жыл бұрын
I think this does what you want: github.com/lefticus/tools/blob/main/include/lefticus/tools/static_views.hpp#L74-L80
@chaeyeunpark2 жыл бұрын
So template non-type parameter somehow takes memory region for static variables? This is pretty new. Hope that my project moves to C++20 soon.
@cppweekly2 жыл бұрын
Note that in the version I implemented (as a function) you get different behavior if it's a primitive (not static) or a user defined type. If you do a constexpr template variable instead, as others have said, you get consistent behavior.
@Florian-sh9nf4 ай бұрын
I am flabbergasted.
@surrog2 жыл бұрын
I mean, this is amazing, but this should be solved at the standard so we remove this 'big enough array'
@taw3e82 жыл бұрын
I don't understand why function make_static() makes things static. Could you please link the annotation that appears in 22:35? I can't seem to find it.
@verylongtrain2 жыл бұрын
Basically because when you pass a string as a template parameter, it has to exist statically.
@taw3e82 жыл бұрын
@@verylongtrain but why? I can understand that when you create a class using template it's definition has to exist and if this definition required storing those parameters then surely they should be static, but why would you have to store data that was only passed to a function?
@cppweekly2 жыл бұрын
eel.is/c++draft/temp.param#8 "An id-expression naming a non-type template-parameter of class type T denotes a **static** storage duration object of type const T, known as a template parameter object"
@JohnWilliams-gy5yc2 жыл бұрын
P2647 allows static constexpr within constexpr. Does it have a *special* meaning when evaluated within a *'real'* constexpr?
@cppweekly Жыл бұрын
Interesting, I didn't know about p2647. It appears to have just been approved for C++23. It looks like it will solve this problem and work exactly as expected. github.com/cplusplus/papers/issues/1318
@michaelwaters13582 жыл бұрын
I think its cool that you found this solution but it still seems like a hack to me. That is a lot of work to just get a constexpr string, I pray that somehow this will get handled better in the future
@X_Baron2 жыл бұрын
One person's hack is another person's design pattern! 😄
@dennisrkb2 жыл бұрын
Presumably the difficulty lies in moving dynamically allocated memory out of constexpr land.. what if we wrote a completely constexpr allocator (a simple stack allocator using a static array for example) and fed that to std::string. Would that work?
@cppweekly2 жыл бұрын
That was one of the original solutions proposed for making the containers constexpr capable. It might work again today. I was thinking about trying to write my own constexpr capable PMR adapter to test with.
@stephenhowe41072 жыл бұрын
This feels like a Frankenstein object.
@ZackFair7132 жыл бұрын
why are you specifying the return value of 'to_string_view' with '->' instead of replacing the 'auto' return type? I thought you only should use the '->' when using 'decltype'
@cppweekly2 жыл бұрын
It's just a style choice. auto func(); // fully compile-time deduced auto func() -> auto; // same as above decltype(auto) func(); // "perfect returning" compile-time deduction auto func() -> decltype(auto); // same as above auto func() -> std::string_view; // trailing return type. this is the same for lambdas: [](){ /*return something*/ } // let the compiler deduce the return type []() -> auto { /*... */} // pointless but valid []() -> std::string_view { /*...*/ } // the only way to specify the return type of a lambda.
@friedkeenan2 жыл бұрын
Hmm, this would all be so much simpler if there were a way to distinguish between memory leaked at compile time and memory that you just want translated into e.g. rodata for runtime. Maybe constexpr on a variable could signify that? but then how do you tell what memory belongs to that variable? very tough issue
@cppweekly2 жыл бұрын
Originally the proposal for constexpr new/delete was going to automatically create static data in objects that "leaked" to compile time. However, they couldn't agree on that feature. Which as you point out, is a complicated question.
@friedkeenan2 жыл бұрын
@@cppweekly I've thought more on this, and I've thought that _maybe_ the constexpr engine could run the destructor of the object, see if all the memory allocated in that expression is freed, and then sorta roll back that destruction. But then that brings up issues of const-ness, like if a unique_ptr is stored as a constexpr variable, it itself would be const but would the data it points to be? I would lean towards yes it would have to be but that might break the semantics of a const unique_ptr. Maybe only unique_ptr could be stored as a constexpr variable? Very tricky
@aDifferentJT2 жыл бұрын
Why is make_static a consteval function template rather than a static constexpr variable template?
@cppweekly2 жыл бұрын
because I had not considered that option when I created it. I have implemented it as an inline constexpr variable template in the library version.
@ysakhno2 жыл бұрын
And where is the name of that template parameter object is stored, and how much space that name occupies?
@cppweekly2 жыл бұрын
There exists the possibility of symbol table bloat, yes.
@davidtzur1363 Жыл бұрын
Why there is (almost) never a link to the source code you are showing. Could save me a lots of time....
@cppweekly Жыл бұрын
This is changing now that all show notes are managed via github. See here github.com/lefticus/cpp_weekly/issues/
@DamianReloaded2 жыл бұрын
Very nice!
@antoniocs88732 жыл бұрын
Weren't all these new c++ additions suppose to help the developer? I'm getting more and more confused. You really cannot learn C++ unless you know all kind of weird tricks...
@cppweekly2 жыл бұрын
These are esoteric techniques that are highly unlikely to impact normal code.
@antoniocs88732 жыл бұрын
@@cppweekly Lets hope you're right
@GreatTutorialChannel Жыл бұрын
Impressive, but for me more a demonstration C++ is partly "broken". it should be a tool to be productive. Not a tool that fights back.
@ohwow20742 жыл бұрын
Exactly the problem that had been searching for a solution for a while. However this is still disgusting and not satisfying. There should be a much simpler way to do this really. This is an embarrassing scenario in 2022.
@diketarogg2 жыл бұрын
Can't you just copy the string literal into a std::array three times without using std::string?
@cppweekly2 жыл бұрын
std::string is much easier to work with in many ways. The goal is to figure out how to make the code easy to work with with fewer human made decisions at compile time.
@johnhsu54592 жыл бұрын
To be honest, I think the source of these problem is "you have to delete the thing you new"
@PedroOliveira-sl6nw2 жыл бұрын
One thing I did not understand is: that works starting on which c++ standard? 23 only?
@therealchonk2 жыл бұрын
c++20 and GCC 12, because std::string must be constexpr.
@cppweekly2 жыл бұрын
yes should be fully C++20 capable. The two-step process (oversized->right sized, followed by static-constexpr) can work in C++17, if you have some other kind of stack-based runtime sized data.
@GeofftheMedio2 жыл бұрын
@@cppweekly Can that process be wrapped cleanly in an operator+ function that can compile-time concatenate two string_view in C++17 ?
@Swedishnbkongu2 жыл бұрын
I'm not sure the oversized array is necessary. Within the make function it's no worse to make an oversized array AND THEN fix it than it is to get the right size the first time (check size first, instantiate array)
@tonydelamancha55132 жыл бұрын
But what about the terminating mill on the string!
@cppweekly2 жыл бұрын
Irrelevant - std::string_view (which is what I want) is not null-terminated.
@c0d3_m0nk3y2 жыл бұрын
@@cppweekly Which is super annoying if you want to pass a string_view to a function that accepts a C string (means you have to copy it).
@MatthewWalker02 жыл бұрын
content-addressable static data??? Never would I have presumed such a thing to exist...
@cppweekly2 жыл бұрын
This is a huge technique that I used when making this talk: kzbin.info/www/bejne/g5XVl4OJitmAjK8
@alexandernomadmain2 жыл бұрын
cool
@blablabla77962 жыл бұрын
10*1024*1024 isn’t 10megabytes right? That’s 10 mebibyte. Mega is an SI term and should mean 10^6.
@cppweekly2 жыл бұрын
I'm old
@iamjadedhobo2 жыл бұрын
The distinction was introduced by harddisk vendors to sell undersized drives. If you bought 1K memory chips there were for sure 1024 bits (or bytes depending on chip type) in that chip. An 2716 EPROM was a 16Kbit device containing 16384 memory bits. HD vendors could swindle you out of a few Mbytes of storage on a Gb size advertised device if they could make you accept their "SI" units deception.
@blablabla77962 жыл бұрын
@@iamjadedhobo hard disk vendors today sell storage in SI units and not in the binary powers not because of some conspiracy to cut costs but because the actual usable space is below the binary bytes value. You can’t actually fill up a 1GB hard drive with 2^30 bytes of information. A portion of that has to be reserved for the storage formatting. Some of it for the device’s background processes. A distinction between these two types of prefixes are important because a lot of computing power would go into physical processes. You wouldn’t want missile guidance systems to mess up just because the computer guy wants k to mean an even 1024 right? Besides, it’s an extra letter away as a prefix and has the same number of syllables when read out loud.
@fromgermany2712 жыл бұрын
Concentrate on the topic, not on some side areas!
@blablabla77962 жыл бұрын
@@fromgermany271 you can do both? Which is pretty much in the spirit of C++ anyway. We go from top level systems all the way down to the bare metal level. From the main point all the way into the side details. C++ programmers aren’t afraid to discuss any aspect.