I actually didn't find anything but the lambda to be strange at all. Even then, when you explained it , the lambda made sense to me. All you have to do is consider constexpr as a formalization of compile time optimizations. const tells the compiler the value will not change. Therefore, compilers are free to substitute a variable for the constant data, and it always makes sense to do so for ints. As a test, I ran the make_value example on C++03 with "-O1." Just switching auto to int, constexpr to const and static_assert to assert. The main function stays 2 instructions!
The unused lambda capture warning is checking whether the variable was ODR-used. During code review, I was told to remove the phrase ODR-used from the warning message.
Strange? This was default how you could handle compile time constants in older code, `constexpr` is more a normalization and be more explicit of this behavior.
The captures thing is not surprising if you remember that lambda captures correspond to member fields of a lambda object. Since constexpr values are known at compile time, they don't require to be stored/loaded at run time and thus they don't need a member field.
surprising thing for me is that you don't need to capture those variables. Rest I expected to work because 42, x = 10, and 20 is known at compile time, so result of lambda is also known at compile time.
The no need to capture x is indeed strange. Trying something similar with a struct instead of int doesn't work. #include struct Pair{ int x; int y; }; int main() { constexpr Pair x{20, 30}; constexpr auto sum = [](){return x.x + x.y;}; printf("%d", sum()); return 0; } last line fails to compile on gcc 14.2 ('x' is not captured). Works if static is added to x definition.
You can think of it as the 'const' being replaced by the compiler with 'static constexpr'. Lambdas can refer to static variables without capture, just like globals.
I guess it would be less surprising if x and value was moved outside of main. I would assume all global constants could be reached from within the lambda
You can think of it as the 'const' being replaced by the compiler with 'static constexpr'. Lambdas can refer to static variables without capture, just like globals.
Is it implicit or is it because of the static_assert? I would imagine that static_assert forces the compiler to do more work and check if the condition can be known at compile time; at which point, the compiler would check if result can be known at compile time; and it back propagates to the two initializations, which can be known at compile time. I think of this as the namespace lookup rules or SFINAE kind of approach. It tries until it fails or succeeds to make it constexpr in its entirety.
Recall that constexpr only means that it can be computed at compile time but doesn't guarantee it is done then. So implicit is accurate even if the static_assert is what forces the compiler to compute the value at compile time.
I'm not quite certain how std::function or lambdas are implemented, but to me the non-explicit capturing thing could make a little sense. At least in the sense, that constexpr values do not require any dynamic state to be bound to a function object (kind of obvious for primitive types, not sure about more complex types).
Sorry, I don't really do online training or mentorship. The best I can offer is that you become a Patron (links in video description) and join my Discord. You can ask questions there and I do my best to answer as soon as possible.
I don't understand the logic behind implicit constexpr capture in lambdas. IMO, rules of language should contain as less as possible "if"s in their definition.
constexpr values are compile-time constants. lambda captures change the size and shape of the lambda, it must now have storage for the values and they are no longer implicitly convertible to function pointers. I think this is a good and logical decision.
I'm sure you would expect me to say that I would expect that kind of behavior by default anyway and this is how my own language works, but minus a lot of that unnecessary verbiage. For instance, in my language there is no constexpr or consteval and no need for them as everything that can be is evaluated at compilation time, and one can use const to tag a block of code or whatever you want to assign an expression to and the only reason to bother tagging something as const is to error check yourself and your assumptions about what can be evaluated at compile time. Basically, if you tag something as const in my language and it can't be evaluated at compile time, then you get an error pointing out where it can't be. As an example, even though I doubt anyone will read this or be curious, if you have `const { i := some_library_function(); puts( "{i+10} " ); }` then it'll be an error if the compiler can't see inside that library and evaluate it.
@@Spielix I would say somewhat less correct. It is linguistically non-standard while not conveying additional information. Secondly, specific items are integers while an integral quantity is an amount representable as an integer in the abstract.
@@mytech6779 In this context integral is just short for integral type and not all integral types are commonly called integers (e.g. chars and bools). So if you mean integral types saying integers would be less correct.
@@mytech6779 Truthfully, it's a quick and dirty way of not specifying the type of integer that it is no matter which way it's said. Sadly, the standard has changed enough on this particular issue that it could be invalidated easily by a future revision for him to say what size integer it actually is. However, I would consider it equally as correct to say integral or integer, but integral fits more here in the context in which he was talking because he wasn't intending to specify a specific integer despite using one as an example.
god this all just looks cursed like something that will immediately put off experienced and new developers alike especially the lambda capture thing, that just seems confusing
@@arthurmoore9488 in C# and Python lambdas implicitly capture everything from the enclosing scope?!?!?! holy cow what a mess... Even PHP didn't do that when it added lambdas back then in v5.
It's probably not a topic for beginners. I've been using C++ for 30 years and never used any of this stuff. Most of the codebases I've worked on a pretty much C++98 syntactically, even though we're using modern compilers.
0:39 yes, my coworkers definitely need some training. Not me, of course, I already know all there is to know about C++ :p
Tell your team lead to email me :D
I actually didn't find anything but the lambda to be strange at all. Even then, when you explained it , the lambda made sense to me. All you have to do is consider constexpr as a formalization of compile time optimizations.
const tells the compiler the value will not change. Therefore, compilers are free to substitute a variable for the constant data, and it always makes sense to do so for ints.
As a test, I ran the make_value example on C++03 with "-O1." Just switching auto to int, constexpr to const and static_assert to assert. The main function stays 2 instructions!
The unused lambda capture warning is checking whether the variable was ODR-used. During code review, I was told to remove the phrase ODR-used from the warning message.
Strange? This was default how you could handle compile time constants in older code, `constexpr` is more a normalization and be more explicit of this behavior.
The captures thing is not surprising if you remember that lambda captures correspond to member fields of a lambda object. Since constexpr values are known at compile time, they don't require to be stored/loaded at run time and thus they don't need a member field.
surprising thing for me is that you don't need to capture those variables. Rest I expected to work because 42, x = 10, and 20 is known at compile time, so result of lambda is also known at compile time.
The no need to capture x is indeed strange.
Trying something similar with a struct instead of int doesn't work.
#include
struct Pair{ int x; int y; };
int main()
{
constexpr Pair x{20, 30};
constexpr auto sum = [](){return x.x + x.y;};
printf("%d", sum());
return 0;
}
last line fails to compile on gcc 14.2 ('x' is not captured).
Works if static is added to x definition.
You can think of it as the 'const' being replaced by the compiler with 'static constexpr'. Lambdas can refer to static variables without capture, just like globals.
I guess it would be less surprising if x and value was moved outside of main. I would assume all global constants could be reached from within the lambda
Jason, the bots find your videos "very informative and interesting". I hope that's encouraging to you.
Devin AI is evolving, and its coming for your job...
Apparently his memes inspire them too
Well that was fun!
Not particularly surprising except the implicit capture of constexpr locals. Feels like some Java type stuff
You can think of it as the 'const' being replaced by the compiler with 'static constexpr'. Lambdas can refer to static variables without capture, just like globals.
Are we eventually going to move everything from constexpr to consteval?
no, many constexpr functions, like all from are also usable at runtime, not only at compiletime
@@Voy2378 right
Is it implicit or is it because of the static_assert? I would imagine that static_assert forces the compiler to do more work and check if the condition can be known at compile time; at which point, the compiler would check if result can be known at compile time; and it back propagates to the two initializations, which can be known at compile time.
I think of this as the namespace lookup rules or SFINAE kind of approach. It tries until it fails or succeeds to make it constexpr in its entirety.
I think it's implicit. Remove static assertion and test by other means and you'll see that const simply means constexpr in these cases.
Recall that constexpr only means that it can be computed at compile time but doesn't guarantee it is done then. So implicit is accurate even if the static_assert is what forces the compiler to compute the value at compile time.
it's implicit, but we need the static_assert to actually see what it did.
Any can pass standard reference to this pls??
I'm not quite certain how std::function or lambdas are implemented, but to me the non-explicit capturing thing could make a little sense. At least in the sense, that constexpr values do not require any dynamic state to be bound to a function object (kind of obvious for primitive types, not sure about more complex types).
Do you have any online training course for intermediate coder?
Sorry, I don't really do online training or mentorship. The best I can offer is that you become a Patron (links in video description) and join my Discord. You can ask questions there and I do my best to answer as soon as possible.
Thanks! I'll try not to abuse this knowledge :-)
In this example, if we return the lambda from the function which refers to local constexpr variable, is calling that lambda an undefined behaviour?
It is not - no object has been captured - only the value has been "captured" (it's going to behave more like a #define internally)
Is this subject to compiler optimization options? I mean #pragma optimize( "", off ) should disable this behavior, right?
Not if it is a language feature... which it apparently is.
@@Spielix Correct - language feature.
I don't understand the logic behind implicit constexpr capture in lambdas.
IMO, rules of language should contain as less as possible "if"s in their definition.
constexpr values are compile-time constants.
lambda captures change the size and shape of the lambda, it must now have storage for the values and they are no longer implicitly convertible to function pointers. I think this is a good and logical decision.
nonsensical! (😉) But very interesting. Always more to learn with C++, thanks Jason!
The bots are fast wtf
They are just big C++ weekly fans.
No wonder, considering how informative and informative these videos are
That's why they are botnics! but what is the point of those?
Loads of background sound on this particular video.
Ok Mr AI Bot
Say what? How do you work that one out? Did you listen to the video? It's noisey, and they usually aren't.
@@peternimmo74 I might have missed a filter. Sorry about that!
I'm sure you would expect me to say that I would expect that kind of behavior by default anyway and this is how my own language works, but minus a lot of that unnecessary verbiage. For instance, in my language there is no constexpr or consteval and no need for them as everything that can be is evaluated at compilation time, and one can use const to tag a block of code or whatever you want to assign an expression to and the only reason to bother tagging something as const is to error check yourself and your assumptions about what can be evaluated at compile time. Basically, if you tag something as const in my language and it can't be evaluated at compile time, then you get an error pointing out where it can't be. As an example, even though I doubt anyone will read this or be curious, if you have `const { i := some_library_function(); puts( "{i+10}
" ); }` then it'll be an error if the compiler can't see inside that library and evaluate it.
integers, not integrals 😅
Integral is correct/more general. See std::is_integral.
I have encountered some math textbooks that called integers/whole numbers as integral numbers so I guess it is fine
@@Spielix I would say somewhat less correct. It is linguistically non-standard while not conveying additional information. Secondly, specific items are integers while an integral quantity is an amount representable as an integer in the abstract.
@@mytech6779 In this context integral is just short for integral type and not all integral types are commonly called integers (e.g. chars and bools). So if you mean integral types saying integers would be less correct.
@@mytech6779 Truthfully, it's a quick and dirty way of not specifying the type of integer that it is no matter which way it's said. Sadly, the standard has changed enough on this particular issue that it could be invalidated easily by a future revision for him to say what size integer it actually is. However, I would consider it equally as correct to say integral or integer, but integral fits more here in the context in which he was talking because he wasn't intending to specify a specific integer despite using one as an example.
god this all just looks cursed
like something that will immediately put off experienced and new developers alike
especially the lambda capture thing, that just seems confusing
welcome to the Javascript world where all captures are implicit lol
@@hijarian Same with C#, Python, and pretty much any interpreted language.
@@arthurmoore9488 in C# and Python lambdas implicitly capture everything from the enclosing scope?!?!?! holy cow what a mess... Even PHP didn't do that when it added lambdas back then in v5.
It's probably not a topic for beginners. I've been using C++ for 30 years and never used any of this stuff. Most of the codebases I've worked on a pretty much C++98 syntactically, even though we're using modern compilers.
@@toby9999 when you say syntactically I guess (or rather hope) that you still use some of the newer features (especially std library)