Excellent explanation. I stumbled into this in Nico's book on templates and to say I was confused beyond words is an understatement with the way it was introduced out of nowhere followed by an awful example given for tree traversal without any clear explanation of what 'op' could be!!! Thanks again for making this incredibly easy to understand.
@@bitsofq One thing you could have mentioned though.. How to deal with an empty parameter pack. For example, if we define the "sum" function that has a minimum of 2 arguments, but the rest (parameter pack) can be of size zero or more. For example: template auto sum(T1 a, T2 b, T... args) { return a + b + (... + args); } This will create a problem if we call sum(1, 2) as parameter pack is empty. But, changing the return value to return a + b + (0 + ... + args); does the trick.
I did mention it at 00:57 but I might have gone over it a bit quick. It's always better to just demonstrate the problem instead of only saying it. Thanks for the feedback! I'm new to making UA-cam videos and always trying to improve, so good feedback is always appreciated!
Fold expressions are a way to tell the compiler how an operator (such as the + or - operator) needs to be applied to a parameter pack. Though the compiler expands the expression at compile time, the actual application of the operator still happens at run time. E.g. (PACK - ...), Expands to (pack - ( pack1 - pack2 )) etc at compile time. This expression, is then evaluated ar runtime (which is why the parameter pack can contain runtime data). Since parameter packs are a compile time construct, you need a way to "translate" them to an expression that can be evaluated at runtime. Folds are one such way, another alternative would be recursion, but this is often harder to read/maintain and takes a higher toll on compilation time. I hope this answers your question. If not, feel free to leave another comment and I'll try to elaborate on my answer.
Just one more note: I just want to clarify that fold expressions are indeed used for when you have a parameter pack (i.e. when you want to write a function that takes an arbitrary nr of inputs). If your data is not in a parameter pack, but in normal container, you most probably would not use a fold expression. For example, if you want to add all values in an std::vector you just use an std::accumulate (see also my series on algorithms from the standard library ua-cam.com/play/PLWxziGKTUvQFVSW_xNZEXufvaYuqKeBa1.html 😉)
A parameter pack is not a type, it just a compile time construct and doesn't exist outside of compile time. In theory you could turn a vector into a parameter pack, but it is quite tricky as vectors have a dynamic size which is only known at runtime. This would be easier for an std::array (For example: godbolt.org/z/63Ys6K8aW) Of course, if you already have your booleans in a container, turning them into a parameter pack just to check if they are all true is a bit convoluted. Usually you would have different data that is already in the form of a parameter pack and you want to apply a predicate to each value/type giving you a pack of booleans which you can then use a fold on. Like this: godbolt.org/z/jfeT4j9ve
Ranges are actually already available in C++20, but the ranges library is indeed being extended in 2023. That being said, support for ranges is lagging behind a bit. Especially the clang compiler only just implemented the basic features of the C++20 standard in their latest version :(
"The operators are applied towards the side of the parameter pack" is a helpful mnemonic, thanks!
Very helpful video. Thanks bro
Excellent explanation. I stumbled into this in Nico's book on templates and to say I was confused beyond words is an understatement with the way it was introduced out of nowhere followed by an awful example given for tree traversal without any clear explanation of what 'op' could be!!! Thanks again for making this incredibly easy to understand.
Great explanation of fold expressions!
Thanks, I'm glad you liked video!
@@bitsofq One thing you could have mentioned though.. How to deal with an empty parameter pack. For example, if we define the "sum" function that has a minimum of 2 arguments, but the rest (parameter pack) can be of size zero or more. For example:
template
auto sum(T1 a, T2 b, T... args) {
return a + b + (... + args);
}
This will create a problem if we call sum(1, 2) as parameter pack is empty. But, changing the return value to
return a + b + (0 + ... + args);
does the trick.
I did mention it at 00:57 but I might have gone over it a bit quick. It's always better to just demonstrate the problem instead of only saying it. Thanks for the feedback!
I'm new to making UA-cam videos and always trying to improve, so good feedback is always appreciated!
@@bitsofq You are correct. I did miss it. My mistake.
thanks man! the CPP ref was hard to understand, this made it easy
Thanks! Great to hear the video was helpful!
thanks
Nice video, it helped me to understand more about fold expressions :D
Thanks!
Glad to hear it was useful!
Why would I use a fold compared to writing it myself during runtime?
Fold expressions are a way to tell the compiler how an operator (such as the + or - operator) needs to be applied to a parameter pack. Though the compiler expands the expression at compile time, the actual application of the operator still happens at run time. E.g. (PACK - ...), Expands to (pack - ( pack1 - pack2 )) etc at compile time. This expression, is then evaluated ar runtime (which is why the parameter pack can contain runtime data).
Since parameter packs are a compile time construct, you need a way to "translate" them to an expression that can be evaluated at runtime. Folds are one such way, another alternative would be recursion, but this is often harder to read/maintain and takes a higher toll on compilation time.
I hope this answers your question. If not, feel free to leave another comment and I'll try to elaborate on my answer.
Just one more note:
I just want to clarify that fold expressions are indeed used for when you have a parameter pack (i.e. when you want to write a function that takes an arbitrary nr of inputs).
If your data is not in a parameter pack, but in normal container, you most probably would not use a fold expression. For example, if you want to add all values in an std::vector you just use an std::accumulate (see also my series on algorithms from the standard library ua-cam.com/play/PLWxziGKTUvQFVSW_xNZEXufvaYuqKeBa1.html 😉)
Is pack in the end , is vector ??
BTW ,Thanks for great video 🙏
Not sure what you mean by "Is pack in the end , is vector ??" Could you clarify?
Happy you enjoyed the video!
7:29 , bool all_true=(pack && .....)
Pack is vector?
A parameter pack is not a type, it just a compile time construct and doesn't exist outside of compile time. In theory you could turn a vector into a parameter pack, but it is quite tricky as vectors have a dynamic size which is only known at runtime. This would be easier for an std::array (For example: godbolt.org/z/63Ys6K8aW)
Of course, if you already have your booleans in a container, turning them into a parameter pack just to check if they are all true is a bit convoluted. Usually you would have different data that is already in the form of a parameter pack and you want to apply a predicate to each value/type giving you a pack of booleans which you can then use a fold on. Like this: godbolt.org/z/jfeT4j9ve
❤️❤️
Oh C++, always the ugliest and wrong defaults. Thankfully C++23 ranges are coming.
Ranges are actually already available in C++20, but the ranges library is indeed being extended in 2023. That being said, support for ranges is lagging behind a bit. Especially the clang compiler only just implemented the basic features of the C++20 standard in their latest version :(