## Fold expressions * Folding is a new way of handling argument package * It can be one or two arguments * If it is two arguments we distinguish between * left folding * right folding ___ ### Fold expressions - adding values ```C++ template int add(Args... args) { return (args + ...); } int main() { std::cout << add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) << '\n'; std::cout << add() << '\n'; // Not compile! } ``` ```C++ 55 ``` ___ ### Fold expressions - adding values ```C++ template int add(Args... args) { return (args + ... + 0); } int main() { std::cout << add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) << '\n'; std::cout << add() << '\n'; // OK } ``` ```C++ 55 0 ``` ___ ### Fold expressions - subtracting values ```C++ template int subR(Args... args) { return (args - ...); } template int subL(Args... args) { return (... - args); } int main() { // (1 - 2) std::cout << subR(1, 2) << '\n'; // -1 // (1 - 2) std::cout << subL(1, 2) << '\n'; // -1 // (1 - (2 - 3)) std::cout << subR(1, 2, 3) << '\n'; // 2 // ((1 - 2) - 3) std::cout << subL(1, 2, 3) << '\n'; // -4 // (1 - (2 - (3 - 4))) std::cout << subR(1, 2, 3, 4) << '\n'; // -2 // (((1 - 2) - 3) - 4) std::cout << subL(1, 2, 3, 4) << '\n'; // -8 // (1 - (2 - (3 - (4 - 5)))) std::cout << subR(1, 2, 3, 4, 5) << '\n'; // 3 // ((((1 - 2) - 3) - 4) - 5) std::cout << subL(1, 2, 3, 4, 5) << '\n'; // -13 } ``` ___ ### Fold expressions - make code work without parameters Find a problem with the below code. ```C++ template int subR(Args... args) { return (args - ... - 0); } template int subL(Args... args) { // What's wrong here??? return (0 - ... - args); } int main() { // (1 - (2 - (3 - (4 - 5)))) std::cout << subR(1, 2, 3, 4, 5) << '\n'; // ((((1 - 2) - 3) - 4) - 5) std::cout << subL(1, 2, 3, 4, 5) << '\n'; std::cout << subR() << '\n'; std::cout << subL() << '\n'; } ``` ```C++ 3 // (1 - (2 - (3 - (4 - (5 - 0)))) -15 // (((((0 - 1) - 2) - 3) - 4) - 5) 0 0 ``` ___ ## How to demand minimum one variable ```C++ template auto average(Value const& value, Values const&... values) { return (value + ... + values) / (1. + sizeof...(values)); } int main() { std::cout << average(1, 2, 3, 4) << '\n'; // print 2.5 std::cout << average() << '\n' // NOT COMPILE! } ``` ___ ## Calling member functions ```C++ template void loggStateForAll(const Args&... args) { (..., args.loggState()); } struct A { void loggState() const { std::cout << "StateA: good!\n"; } }; struct B { void loggState() const { std::cout << "StateB: bad!\n"; } }; int main() { loggStateForAll(A{}, B{}, A{}, B{}); /* Will print StateA: good! StateB: bad! StateA: good! StateB: bad! */ } ``` ___ ## Fold expressions - insert to container (1) ```C++ class Foo { public: Foo(int num) : num_(num) {} int num() const { return num_; } private: int num_; }; template void emplaceAll(std::vector& vec, Args... args) { (vec.emplace_back(args), ...); } int main() { std::vector vec; emplaceAll(vec, 1, 2, 3, 4, 5, 6, 7); std::transform(cbegin(vec), cend(vec), std::ostream_iterator(std::cout, " "), [](const auto& foo) { return foo.num(); }); } ``` ```C++ 1 2 3 4 5 6 7 ``` * What with (..., vec.emplace_back(args))? ___ ### Fold expressions - insert to container (2) * There is no right/left type of folding for one type of argument * Unary right fold (fun(arg0) , (fun(arg1) , (fun(arg2) , ...))) * Unary left fold (((fun(arg0) , fun(arg1)) , fun(arg2)) , ... * Only for binary folding, we can have different behavior ___ ### Fold expressions - logic operators ```C++ template bool emplaceAll(std::set& set, Args... args) { return (set.insert(args).second && ...); } int main() { std::set set; emplaceAll(set, 1, 2, 3, 4, 5, 1, 6, 7); std::copy(cbegin(set), cend(set), std::ostream_iterator(std::cout, " ")); } ``` ```C++ 1 2 3 4 5 ``` For bot way: return (set.insert(args).second && ...); and return (... && set.insert(args).second); output will be the same ___ ### Fold expressions - cooperation with STL algorithms ```C++ template bool HasAll(const std::vector& vec, Args... args) { return ((std::find(cbegin(vec), cend(vec), args) != std::cend(vec)) && ...); } int main() { std::vector vec{1, 2, 3, 4, 1, 2, 3, 5, 6, 7, 4}; std::cout << std::boolalpha << HasAll(vec, 2, 4, 6) << '\n'; std::cout << std::boolalpha << HasAll(vec, 2, 4, 6, 8) << '\n'; } ``` ```C++ true false ```