6.2 KiB
6.2 KiB
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
template <typename... Args>
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!
}
55
Fold expressions - adding values
template <typename... Args>
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
}
55
0
Fold expressions - subtracting values
template <typename... Args>
int subR(Args... args) {
return (args - ...);
}
template <typename... Args>
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.
template <typename... Args>
int subR(Args... args) {
return (args - ... - 0);
}
template <typename... Args>
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';
}
3 // (1 - (2 - (3 - (4 - (5 - 0))))
-15 // (((((0 - 1) - 2) - 3) - 4) - 5)
0
0
How to demand minimum one variable
template<typename Value, typename... Values>
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
template<typename... Args>
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)
class Foo {
public:
Foo(int num)
: num_(num) {}
int num() const { return num_; }
private:
int num_;
};
template <typename... Args>
void emplaceAll(std::vector<Foo>& vec, Args... args) {
(vec.emplace_back(args), ...);
}
int main() {
std::vector<Foo> vec;
emplaceAll(vec, 1, 2, 3, 4, 5, 6, 7);
std::transform(cbegin(vec), cend(vec), std::ostream_iterator<int>(std::cout, " "),
[](const auto& foo) { return foo.num(); });
}
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
template <typename... Args>
bool emplaceAll(std::set<int>& set, Args... args) {
return (set.insert(args).second && ...);
}
int main() {
std::set<int> set;
emplaceAll(set, 1, 2, 3, 4, 5, 1, 6, 7);
std::copy(cbegin(set), cend(set), std::ostream_iterator<int>(std::cout, " "));
}
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
template <typename... Args>
bool HasAll(const std::vector<int>& vec, Args... args) {
return ((std::find(cbegin(vec), cend(vec), args) != std::cend(vec)) && ...);
}
int main() {
std::vector<int> 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';
}
true
false