280 lines
6.2 KiB
Markdown
280 lines
6.2 KiB
Markdown
## Fold expressions
|
|
|
|
* <!-- .element: class="fragment fade-in" --> Folding is a new way of handling argument package
|
|
* <!-- .element: class="fragment fade-in" --> It can be one or two arguments
|
|
* <!-- .element: class="fragment fade-in" --> If it is two arguments we distinguish between
|
|
* <!-- .element: class="fragment fade-in" --> left folding
|
|
* <!-- .element: class="fragment fade-in" --> right folding
|
|
___
|
|
|
|
### Fold expressions - adding values
|
|
|
|
```C++
|
|
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!
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```C++
|
|
55
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
___
|
|
|
|
### Fold expressions - adding values
|
|
|
|
```C++
|
|
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
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```C++
|
|
55
|
|
0
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
___
|
|
|
|
### Fold expressions - subtracting values
|
|
|
|
```C++
|
|
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
|
|
}
|
|
```
|
|
|
|
<!-- .slide: style="font-size: 0.69em" -->
|
|
___
|
|
|
|
### Fold expressions - make code work without parameters
|
|
|
|
Find a problem with the below code.
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```C++
|
|
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';
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```C++
|
|
3 // (1 - (2 - (3 - (4 - (5 - 0))))
|
|
-15 // (((((0 - 1) - 2) - 3) - 4) - 5)
|
|
0
|
|
0
|
|
```
|
|
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.75em" -->
|
|
___
|
|
|
|
## How to demand minimum one variable
|
|
|
|
```C++
|
|
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
|
|
|
|
```C++
|
|
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! */
|
|
}
|
|
```
|
|
<!-- .slide: style="font-size: 0.74em" -->
|
|
___
|
|
|
|
## Fold expressions - insert to container (1)
|
|
|
|
```C++
|
|
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(); });
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```C++
|
|
1 2 3 4 5 6 7
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
* <b>What with <code>(..., vec.emplace_back(args))</code>?</b>
|
|
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.73em" -->
|
|
___
|
|
|
|
### Fold expressions - insert to container (2)
|
|
|
|
* <!-- .element: class="fragment fade-in" --> There is no right/left type of folding for one type of argument
|
|
* <!-- .element: class="fragment fade-in" --> Unary right fold (fun(arg0) , (fun(arg1) , (fun(arg2) , ...)))
|
|
* <!-- .element: class="fragment fade-in" --> Unary left fold (((fun(arg0) , fun(arg1)) , fun(arg2)) , ...
|
|
* <!-- .element: class="fragment fade-in" --> Only for binary folding, we can have different behavior
|
|
___
|
|
|
|
### Fold expressions - logic operators
|
|
|
|
```C++
|
|
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, " "));
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```C++
|
|
1 2 3 4 5
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<b>For bot way:</b>
|
|
<code>return (set.insert(args).second && ...);</code>
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
<b>and</b>
|
|
<code>return (... && set.insert(args).second);</code>
|
|
<b>output will be the same</b>
|
|
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.90em" -->
|
|
___
|
|
|
|
### Fold expressions - cooperation with STL algorithms
|
|
|
|
```C++
|
|
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';
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```C++
|
|
true
|
|
false
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.8em" -->
|