Slide 1

Slide 1 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 1/208 Function Moar with C++23 Björn Fahller f x y ( , ) + f x y = ( )( ) Currying?

Slide 2

Slide 2 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 2/208

Slide 3

Slide 3 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 3/208 Function Moar with C++23

Slide 4

Slide 4 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 4/208 Function Moar with C++23 I did a talk on this topic in 2018

Slide 5

Slide 5 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 5/208 Function Moar with C++23 I did a talk on this topic in 2018 The core language has evolved since then

Slide 6

Slide 6 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 6/208 Function Moar with C++23 I did a talk on this topic in 2018 The core language has evolved since then The standard library has evolved since then

Slide 7

Slide 7 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 7/208 Function Moar with C++23 I did a talk on this topic in 2018 The core language has evolved since then The standard library has evolved since then I have gained experience since then

Slide 8

Slide 8 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 8/208 template auto func(T t) { return t.a; } auto lambda = [](auto t) { return t.a; }; Function and “function” What are the differences between func and lambda?

Slide 9

Slide 9 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 9/208 template auto func(T t) { return t.a; } auto lambda = [](auto t) { return t.a; }; Function and “function” What are the differences between func and lambda? func can expand to several functions, one for every type T. You cannot get a pointer to func, only to specializations.

Slide 10

Slide 10 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 10/208 template auto func(T t) { return t.a; } auto lambda = [](auto t) { return t.a; }; Function and “function” What are the differences between func and lambda? func can expand to several functions, one for every type T. You cannot get a pointer to func, only to specializations. lambda is one object with several overloaded operator(), one for every type T.

Slide 11

Slide 11 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 11/208 template auto func(T t) { return t.a; } auto lambda = [](auto t) { return t.a; }; Function and “function” What are the differences between func and lambda? func can expand to several functions, one for every type T. You cannot get a pointer to func, only to specializations. lambda is one object with several overloaded operator(), one for every type T. You can take the address of lambda, and you can pass lambda as one object to a higher order function.

Slide 12

Slide 12 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 12/208 template auto func(T t) { return t.a; } auto lambda = [](auto t) { return t.a; }; Function and “function” What are the differences between func and lambda? There is no name for the overload set of specializations for func

Slide 13

Slide 13 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 13/208 template auto func(T t) { return t.a; } auto lambda = [](auto t) { return t.a; }; Function and “function” What are the differences between func and lambda? There is no name for the overload set of specializations for func Whereas lambda is a name for all overloaded function call operators

Slide 14

Slide 14 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 14/208 Test for all numbers being positive template bool all_positive(const R& r) { return std::ranges::all_of(r, [](const auto& v){ return v > 0;}); }

Slide 15

Slide 15 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 15/208 Test for all numbers being positive template bool all_positive(const R& r) { return std::ranges::all_of(r, [](const auto& v){ return v > 0;}); } You will probably write this lambda many times in your program, and it’s noisy

Slide 16

Slide 16 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 16/208 Test for all numbers being positive

Slide 17

Slide 17 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 17/208 auto greater_than = [](auto rh){ return [rh](const auto& lh) { return lh > rh;}; }; template bool all_positive(const R& r) { return std::ranges::all_of(r, [](const auto& v){ return v > 0;}); } Test for all numbers being positive

Slide 18

Slide 18 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 18/208 auto greater_than = [](auto rh){ return [rh](const auto& lh) { return lh > rh;}; }; template bool all_positive(const R& r) { return std::ranges::all_of(r, [](const auto& v){ return v > 0;}); } Test for all numbers being positive Return a lambda that captures the value to compare with

Slide 19

Slide 19 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 19/208 auto greater_than = [](auto rh){ return [rh](const auto& lh) { return lh > rh;}; }; template bool all_positive(const R& r) { return std::ranges::all_of(r, [](const auto& v){ return v > 0;}); } Test for all numbers being positive Return a lambda that captures the value to compare with And returns the result of the comparison when called

Slide 20

Slide 20 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 20/208 auto greater_than = [](auto rh){ return [rh](const auto& lh) { return lh > rh;}; }; template bool all_positive(const R& r) { return std::ranges::all_of(r, [](const auto& v){ return v > 0;}); } Test for all numbers being positive greater_than(0)); Return a lambda that captures the value to compare with And returns the result of the comparison when called

Slide 21

Slide 21 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 21/208 auto greater_than = [](auto rh){ return [rh](const auto& lh) { return lh > rh;}; }; template bool all_positive(const R& r) { return std::ranges::all_of(r, [](const auto& v){ return v > 0;}); } Test for all numbers being positive greater_than(0)); Return a lambda that captures the value to compare with And returns the result of the comparison when called

Slide 22

Slide 22 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 22/208 Test for all numbers being positive

Slide 23

Slide 23 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 23/208 Test for all numbers being positive Added to the standard library in C++23

Slide 24

Slide 24 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 24/208 Test for all numbers being positive Added to the standard library in C++23

Slide 25

Slide 25 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 25/208 Test for all numbers being positive Returns something that when called, calls the function with the direct args and then the bound args

Slide 26

Slide 26 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 26/208 Test for all numbers being positive Compares every value in r with std::greater{}(value, 0)

Slide 27

Slide 27 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 27/208 Test for all numbers being positive Sadly missing in most stdlib implementations

Slide 28

Slide 28 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 28/208 Test for all numbers being positive auto bind_back = [](auto f, auto rh) { return [f, rh](auto lh) { return f(lh, rh); }; };

Slide 29

Slide 29 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 29/208 Test for all numbers being positive auto bind_back = [](auto f, auto rh) { return [f, rh](auto lh) { return f(lh, rh); }; }; Bind the function to call and the right hand side value.

Slide 30

Slide 30 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 30/208 Test for all numbers being positive auto bind_back = [](auto f, auto rh) { return [f, rh](auto lh) { return f(lh, rh); }; }; Call the bound function with the left hand side argument and the bound right hand side value

Slide 31

Slide 31 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 31/208 Test for all numbers being positive auto bind_back = [](auto f, auto rh) { return [f, rh](auto lh) { return f(lh, rh); }; }; auto less_than = [](auto t) { return bind_back(std::less{}, t); }; auto greater_than = [](auto t) { return bind_back(std::greater{}, t); }; template bool all_positive(const R& r) { return std::ranges::all_of(r, greater_than(0)); }

Slide 32

Slide 32 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 32/208 Test for all numbers being positive auto bind_back = [](auto f, auto rh) { return [f, rh](auto lh) { return f(lh, rh); }; }; auto less_than = [](auto t) { return bind_back(std::less{}, t); }; auto greater_than = [](auto t) { return bind_back(std::greater{}, t); }; template bool all_positive(const R& r) { return std::ranges::all_of(r, greater_than(0)); } And now add the rest of the comparisons

Slide 33

Slide 33 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 33/208 https://godbolt.org/z/47cKvn36T

Slide 34

Slide 34 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 34/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } }

Slide 35

Slide 35 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 35/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } Makes a sequence of neighbouring elements as tuples of references

Slide 36

Slide 36 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 36/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } Makes a sequence of neighbouring elements as tuples of references

Slide 37

Slide 37 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 37/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } Makes a sequence of neighbouring elements as tuples of references

Slide 38

Slide 38 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 38/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } Makes a sequence of neighbouring elements as tuples of references

Slide 39

Slide 39 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 39/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } Makes a sequence of neighbouring elements as tuples of references

Slide 40

Slide 40 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 40/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } Makes a sequence of neighbouring elements as tuples of references

Slide 41

Slide 41 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 41/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } Makes a sequence of neighbouring elements as tuples of references

Slide 42

Slide 42 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 42/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } }

Slide 43

Slide 43 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 43/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } }

Slide 44

Slide 44 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 44/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } t is a tuple.

Slide 45

Slide 45 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 45/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } Destructure it to make the code easier on the eyes.

Slide 46

Slide 46 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 46/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } This construction gets old very quickly

Slide 47

Slide 47 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 47/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } Can we use std::apply somehow?

Slide 48

Slide 48 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 48/208 Get the differences in a sequence int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } Can we use std::apply somehow?

Slide 49

Slide 49 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 49/208 Get the differences in a sequence

Slide 50

Slide 50 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 50/208 Get the differences in a sequence auto apply = [](F&& f) { return [f = std::forward(f)](T&& t) { return std::apply(f, std::forward(t)); }; };

Slide 51

Slide 51 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 51/208 Get the differences in a sequence auto apply = [](F&& f) { return [f = std::forward(f)](T&& t) { return std::apply(f, std::forward(t)); }; }; New syntax since C++23 to get explicitly named deduced types to lambda arguments

Slide 52

Slide 52 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 52/208 Get the differences in a sequence auto apply = [](F&& f) { return [f = std::forward(f)](T&& t) { return std::apply(f, std::forward(t)); }; }; New syntax since C++23 to get explicitly named deduced types to lambda arguments

Slide 53

Slide 53 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 53/208 Get the differences in a sequence auto apply = [](F&& f) { return [f = std::forward(f)](T&& t) { return std::apply(f, std::forward(t)); }; }; Return a lambda that captures the function

Slide 54

Slide 54 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 54/208 Get the differences in a sequence auto apply = [](F&& f) { return [f = std::forward(f)](T&& t) { return std::apply(f, std::forward(t)); }; }; Call std::apply with the captured function, and the tuple from the argument list

Slide 55

Slide 55 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 55/208 Get the differences in a sequence auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } }

Slide 56

Slide 56 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 56/208 Get the differences in a sequence auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } apply([](auto a, auto b) { return b - a;})

Slide 57

Slide 57 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 57/208 Get the differences in a sequence auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } apply([](auto a, auto b) { return b - a;}) Less noise. Good!

Slide 58

Slide 58 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 58/208 Get the differences in a sequence auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( [](auto&& t){ auto&& [a,b] = t; return b - a;} )) { std::cout << d << '\n'; } } apply([](auto a, auto b) { return b - a;}) But the standard library has std::minus, can we use it?

Slide 59

Slide 59 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 59/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence Hmm, std::minus, would return a – b. Can we change the order?

Slide 60

Slide 60 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 60/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts)

Slide 61

Slide 61 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 61/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts) Take a function to call

Slide 62

Slide 62 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 62/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts) Take a function to call Is is the order of the arguments to pass

Slide 63

Slide 63 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 63/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts) swizzle<2,0,1>(func)(“string”, 3, nullptr) becomes a call to func(nullptr, “string”, 3)

Slide 64

Slide 64 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 64/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts) As usual, return a lambda that captures the function, and accepts a number of arguments

Slide 65

Slide 65 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 65/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts)

Slide 66

Slide 66 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 66/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts) Create a tuple type with references to all parameters

Slide 67

Slide 67 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 67/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts)

Slide 68

Slide 68 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 68/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts) Create an instance that refers to all parameters

Slide 69

Slide 69 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 69/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts)

Slide 70

Slide 70 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 70/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts) And finally call the function, picking the arguments in the order of Is

Slide 71

Slide 71 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 71/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts) requires ((Is < sizeof...(ts)) && ...) { using Tup = std::tuple; auto tup = Tup(std::forward(ts)...); return f(std::get(std::move(tup))...); }; };

Slide 72

Slide 72 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 72/208 auto apply = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << '\n'; } } Get the differences in a sequence template auto swizzle = [](F&& f) { return [f = std::forward(f)](Ts&& ... ts) requires ((Is < sizeof...(ts)) && ...) { using Tup = std::tuple; auto tup = Tup(std::forward(ts)...); return f(std::get(std::move(tup))...); }; }; And maybe a constraint for slightly less confusing error messages

Slide 73

Slide 73 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 73/208 auto apply = [](F&& f) ... template auto swizzle = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << ' '; } } Get the differences in a sequence

Slide 74

Slide 74 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 74/208 auto apply = [](F&& f) ... template auto swizzle = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << ' '; } } Get the differences in a sequence apply(swizzle<1,0>(std::minus{}))

Slide 75

Slide 75 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 75/208 auto apply = [](F&& f) ... template auto swizzle = [](F&& f) ... int main() { std::array sequence{1,3,8,2,3,8,1}; for (auto d : sequence | std::ranges::views::pairwise | std::ranges::views::transform( apply([](auto a, auto b) { return b - a;}) )) { std::cout << d << ' '; } } Get the differences in a sequence apply(swizzle<1,0>(std::minus{}))

Slide 76

Slide 76 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 76/208 https://godbolt.org/z/jqdYTrcvr

Slide 77

Slide 77 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 77/208 IP addresses struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(const ip_address& rh) const = default; uint32_t num; }; struct netmask : private ip_address { using ip_address::ip_address; friend ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; } };

Slide 78

Slide 78 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 78/208 IP addresses struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(const ip_address& rh) const = default; uint32_t num; }; struct netmask : private ip_address { using ip_address::ip_address; friend ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; } };

Slide 79

Slide 79 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 79/208 IP addresses struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(const ip_address& rh) const = default; uint32_t num; }; struct netmask : private ip_address { using ip_address::ip_address; friend ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; } }; C++20. Default operator== and get != for free!

Slide 80

Slide 80 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 80/208 IP addresses struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(const ip_address& rh) const = default; uint32_t num; }; struct netmask : private ip_address { using ip_address::ip_address; friend ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; } };

Slide 81

Slide 81 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 81/208 IP addresses struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(const ip_address& rh) const = default; uint32_t num; }; struct netmask : private ip_address { using ip_address::ip_address; friend ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; } }; net masks are used to filter addresses for subnets.

Slide 82

Slide 82 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 82/208 IP addresses struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(const ip_address& rh) const = default; uint32_t num; }; struct netmask : private ip_address { using ip_address::ip_address; friend ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; } };

Slide 83

Slide 83 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 83/208 IP addresses struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(const ip_address& rh) const = default; uint32_t num; }; struct netmask : private ip_address { using ip_address::ip_address; friend ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; } }; The filtering is done by bitwise-and between an address and a mask

Slide 84

Slide 84 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 84/208 IP addresses struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(const ip_address& rh) const = default; uint32_t num; }; struct netmask : private ip_address { using ip_address::ip_address; friend ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; } };

Slide 85

Slide 85 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 85/208 IP addresses struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(const ip_address& rh) const = default; uint32_t num; }; struct netmask : private ip_address { using ip_address::ip_address; friend ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; } }; auto ip_matches = [](ip_address desired, netmask mask = {255,255,255,255}) { return [desired, mask](ip_address actual) { return (desired & mask) == (actual & mask); }; };

Slide 86

Slide 86 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 86/208 IP addresses struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(const ip_address& rh) const = default; uint32_t num; }; struct netmask : private ip_address { using ip_address::ip_address; friend ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; } }; auto ip_matches = [](ip_address desired, netmask mask = {255,255,255,255}) { return [desired, mask](ip_address actual) { return (desired & mask) == (actual & mask); }; }; Who sees the pattern?

Slide 87

Slide 87 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 87/208 IP addresses struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(const ip_address& rh) const = default; uint32_t num; }; struct netmask : private ip_address { using ip_address::ip_address; friend ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; } }; auto ip_matches = [](ip_address desired, netmask mask = {255,255,255,255}) { return [desired, mask](ip_address actual) { return (desired & mask) == (actual & mask); }; }; auto it = std::ranges::find_if(addresses, ip_matches({192,168,0,0}, {255,255,0,0})); Use like

Slide 88

Slide 88 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 88/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; };

Slide 89

Slide 89 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 89/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto get_state = std::mem_fn(&ipif::state);

Slide 90

Slide 90 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 90/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto get_state = std::mem_fn(&ipif::state);

Slide 91

Slide 91 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 91/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto get_state = std::mem_fn(&ipif::state); Call to get_state(ipif_obj) becomes a call to ipif_obj.state()

Slide 92

Slide 92 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 92/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto get_state = std::mem_fn(&ipif::state); auto get_address = std::mem_fn(&ipif::address);

Slide 93

Slide 93 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 93/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto get_state = std::mem_fn(&ipif::state); auto get_address = std::mem_fn(&ipif::address); auto get_mask = std::mem_fn(&ipif::address);

Slide 94

Slide 94 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 94/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto get_state = std::mem_fn(&ipif::state); auto get_address = std::mem_fn(&ipif::address); auto get_mask = std::mem_fn(&ipif::address); auto get_gateway = std::mem_fn(&ipif::gateway);

Slide 95

Slide 95 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 95/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto get_state = std::mem_fn(&ipif::state); auto get_address = std::mem_fn(&ipif::address); auto get_mask = std::mem_fn(&ipif::address); auto get_gateway = std::mem_fn(&ipif::gateway); auto set_state = [](ipif::state_type state) { return bind_back(std::mem_fn(&ipif::set_state), state); };

Slide 96

Slide 96 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 96/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; };

Slide 97

Slide 97 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 97/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; How can we find an ipif in a range, given an ip_address?

Slide 98

Slide 98 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 98/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; Given: f1(y) -> z and f2(x) -> y We want a composition f(x)->z as f1(f2(x))

Slide 99

Slide 99 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 99/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; Given: f1(y) -> z and f2(x) -> y We want a composition f(x)->z as f1(f2(x)) get_address(ipif) -> ip_address

Slide 100

Slide 100 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 100/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; Given: f1(y) -> z and f2(x) -> y We want a composition f(x)->z as f1(f2(x)) ip_matches(ip_address) -> bool get_address(ipif) -> ip_address

Slide 101

Slide 101 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 101/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto compose = [] (auto f1, auto f2) { return [f1 , f2 ] (auto ... ts) { return f1(f2( ts ...)); }; }; Given: f1(y) -> z and f2(x) -> y We want a composition f(x)->z as f1(f2(x)) ip_matches(ip_address) -> bool get_address(ipif) -> ip_address

Slide 102

Slide 102 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 102/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto compose = [] (auto f1, auto f2) { return [f1 , f2 ] (auto ... ts) { return f1(f2( ts ...)); }; }; Given: f1(y) -> z and f2(x) -> y We want a composition f(x)->z as f1(f2(x)) ip_matches(ip_address) -> bool get_address(ipif) -> ip_address Return a lambda that captures the functions

Slide 103

Slide 103 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 103/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto compose = [] (auto f1, auto f2) { return [f1 , f2 ] (auto ... ts) { return f1(f2( ts ...)); }; }; Given: f1(y) -> z and f2(x) -> y We want a composition f(x)->z as f1(f2(x)) ip_matches(ip_address) -> bool get_address(ipif) -> ip_address Forward the arguments to the captured functions

Slide 104

Slide 104 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 104/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto compose = [] (auto f1, auto f2) { return [f1 , f2 ] (auto ... ts) { return f1(f2( ts ...)); }; }; Given: f1(y) -> z and f2(x) -> y We want a composition f(x)->z as f1(f2(x)) ip_matches(ip_address) -> bool get_address(ipif) -> ip_address auto compose = [] (auto f1, auto f2) { return [f1 , f2 ] (auto ... ts) -> decltype(auto) { return f1(f2( ts ...)); }; }; In case f1 returns a reference

Slide 105

Slide 105 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 105/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto compose = [] (auto f1, auto f2) { return [f1 , f2 ] (auto ... ts) { return f1(f2( ts ...)); }; }; Given: f1(y) -> z and f2(x) -> y We want a composition f(x)->z as f1(f2(x)) ip_matches(ip_address) -> bool get_address(ipif) -> ip_address auto compose = [] (auto f1, auto f2) { return [f1 , f2 ] (auto ... ts) -> decltype(auto) { return f1(f2( ts ...)); }; }; auto compose = [](F1&& f1, F2&& f2) { return [f1 = std::forward(f1), f2 = std::forward(f2)] (auto ... ts) -> decltype(auto) { return f1(f2( ts ...)); }; }; Perfect forwarding of the functions to call

Slide 106

Slide 106 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 106/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto compose = [] (auto f1, auto f2) { return [f1 , f2 ] (auto ... ts) { return f1(f2( ts ...)); }; }; Given: f1(y) -> z and f2(x) -> y We want a composition f(x)->z as f1(f2(x)) ip_matches(ip_address) -> bool get_address(ipif) -> ip_address auto compose = [] (auto f1, auto f2) { return [f1 , f2 ] (auto ... ts) -> decltype(auto) { return f1(f2( ts ...)); }; }; auto compose = [](F1&& f1, F2&& f2) { return [f1 = std::forward(f1), f2 = std::forward(f2)] (auto ... ts) -> decltype(auto) { return f1(f2( ts ...)); }; }; auto compose = [](F1&& f1, F2&& f2) { return [f1 = std::forward(f1), f2 = std::forward(f2)] (Ts&& ... ts) -> decltype(auto) { return f1(f2(std::forward(ts)...)); }; }; Perfect forwarding of arguments

Slide 107

Slide 107 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 107/208

Slide 108

Slide 108 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 108/208 ● In functional programming, a family of higher order functions that only deals with composing functions, is called combinators

Slide 109

Slide 109 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 109/208 ● In functional programming, a family of higher order functions that only deals with composing functions, is called combinators ● There are many well known combinators

Slide 110

Slide 110 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 110/208 ● In functional programming, a family of higher order functions that only deals with composing functions, is called combinators ● There are many well known combinators https://youtu.be/JELcdZLre3s

Slide 111

Slide 111 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 111/208 ● In functional programming, a family of higher order functions that only deals with composing functions, is called combinators ● There are many well known combinators

Slide 112

Slide 112 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 112/208 ● In functional programming, a family of higher order functions that only deals with composing functions, is called combinators ● There are many well known combinators ● They have names like B, C*, O, F**, J...

Slide 113

Slide 113 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 113/208 ● In functional programming, a family of higher order functions that only deals with composing functions, is called combinators ● There are many well known combinators ● They have names like B, C*, O, F**, J... ● And their ornithological counterparts Bluebird, Cardinal once removed, Owl, Finch twice removed, Jay...

Slide 114

Slide 114 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 114/208 ● In functional programming, a family of higher order functions that only deals with composing functions, is called combinators ● There are many well known combinators ● They have names like B, C*, O, F**, J... ● And their ornithological counterparts Bluebird, Cardinal once removed, Owl, Finch twice removed, Jay...

Slide 115

Slide 115 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 115/208 ● In functional programming, a family of higher order functions that only deals with composing functions, is called combinators ● There are many well known combinators ● They have names like B, C*, O, F**, J... ● And their ornithological counterparts Bluebird, Cardinal once removed, Owl, Finch twice removed, Jay... ● https://hackage.haskell.org/package/data-aviary-0.4.0/docs/Data-Aviary-Birds.html

Slide 116

Slide 116 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 116/208 ● In functional programming, a family of higher order functions that only deals with composing functions, is called combinators ● There are many well known combinators ● They have names like B, C*, O, F**, J... ● And their ornithological counterparts Bluebird, Cardinal once removed, Owl, Finch twice removed, Jay... ● https://hackage.haskell.org/package/data-aviary-0.4.0/docs/Data-Aviary-Birds.html ● The one I wrote is the B-combinator or Bluebird

Slide 117

Slide 117 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 117/208 ● In functional programming, a family of higher order functions that only deals with composing functions, is called combinators ● There are many well known combinators ● They have names like B, C*, O, F**, J... ● And their ornithological counterparts Bluebird, Cardinal once removed, Owl, Finch twice removed, Jay... ● https://hackage.haskell.org/package/data-aviary-0.4.0/docs/Data-Aviary-Birds.html ● The one I wrote is the B-combinator or Bluebird ● I just cant…

Slide 118

Slide 118 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 118/208 ● In functional programming, a family of higher order functions that only deals with composing functions, is called combinators ● There are many well known combinators ● They have names like B, C*, O, F**, J... ● And their ornithological counterparts Bluebird, Cardinal once removed, Owl, Finch twice removed, Jay... ● https://hackage.haskell.org/package/data-aviary-0.4.0/docs/Data-Aviary-Birds.html ● The one I wrote is the B-combinator or Bluebird ● I just cant… ● https://en.wikipedia.org/wiki/Function_composition

Slide 119

Slide 119 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 119/208 ● In functional programming, a family of higher order functions that only deals with composing functions, is called combinators ● There are many well known combinators ● They have names like B, C*, O, F**, J... ● And their ornithological counterparts Bluebird, Cardinal once removed, Owl, Finch twice removed, Jay... ● https://hackage.haskell.org/package/data-aviary-0.4.0/docs/Data-Aviary-Birds.html ● The one I wrote is the B-combinator or Bluebird ● I just cant… ● ● I’m sticking with compose(x, y), sorry... https://en.wikipedia.org/wiki/Function_composition

Slide 120

Slide 120 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 120/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto compose = [](F1&& f1, F2&& f2) { return [f1 = std::forward(f1), f2 = std::forward(f2)] (Ts&& ... ts) -> decltype(auto) { return f1(f2(std::forward(ts)...)); }; };

Slide 121

Slide 121 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 121/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto compose = [](F1&& f1, F2&& f2) { return [f1 = std::forward(f1), f2 = std::forward(f2)] (Ts&& ... ts) -> decltype(auto) { return f1(f2(std::forward(ts)...)); }; }; auto with_address = [](auto addr, netmask mask = {255,255,255,255}) { return compose(ip_matches(addr, mask), get_address); }; auto it = std::ranges::find_if(interfaces, compose(ip_matches({192,168,0,1}, get_address))); Use like

Slide 122

Slide 122 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 122/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto compose = [](F1&& f1, F2&& f2) { return [f1 = std::forward(f1), f2 = std::forward(f2)] (Ts&& ... ts) -> decltype(auto) { return f1(f2(std::forward(ts)...)); }; }; auto with_address = [](auto addr, netmask mask = {255,255,255,255}) { return compose(ip_matches(addr, mask), get_address); }; auto it = std::ranges::find_if(interfaces, compose(ip_matches({192,168,0,1}, get_address)));

Slide 123

Slide 123 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 123/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto compose = [](F1&& f1, F2&& f2) { return [f1 = std::forward(f1), f2 = std::forward(f2)] (Ts&& ... ts) -> decltype(auto) { return f1(f2(std::forward(ts)...)); }; }; auto with_address = [](auto addr, netmask mask = {255,255,255,255}) { return compose(ip_matches(addr, mask), get_address); }; auto it = std::ranges::find_if(interfaces, compose(ip_matches({192,168,0,1}, get_address)));

Slide 124

Slide 124 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 124/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto compose = [](F1&& f1, F2&& f2) { return [f1 = std::forward(f1), f2 = std::forward(f2)] (Ts&& ... ts) -> decltype(auto) { return f1(f2(std::forward(ts)...)); }; }; auto with_address = [](auto addr, netmask mask = {255,255,255,255}) { return compose(ip_matches(addr, mask), get_address); }; auto it = std::ranges::find_if(interfaces, compose(ip_matches({192,168,0,1}, get_address))); with_address({192,168,0,1}));

Slide 125

Slide 125 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 125/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto compose = [](F1&& f1, F2&& f2) { return [f1 = std::forward(f1), f2 = std::forward(f2)] (Ts&& ... ts) -> decltype(auto) { return f1(f2(std::forward(ts)...)); }; }; auto with_address = [](auto addr, netmask mask = {255,255,255,255}) { return compose(ip_matches(addr, mask), get_address); }; auto it = std::ranges::find_if(interfaces, compose(ip_matches({192,168,0,1}, get_address))); with_address({192,168,0,1})); But what if I want to search with more than one criteria, e.g. address and state?

Slide 126

Slide 126 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 126/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; };

Slide 127

Slide 127 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 127/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto when_all = [](Fs&& ... fs) { return [...fs = std::forward(fs)](const auto& ... ts) { return (fs(ts...) && ...);         }; };

Slide 128

Slide 128 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 128/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto when_all = [](Fs&& ... fs) { return [...fs = std::forward(fs)](const auto& ... ts) { return (fs(ts...) && ...);         }; }; C++23 syntax to capture a whole parameter pack without resorting to tuples

Slide 129

Slide 129 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 129/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto when_all = [](Fs&& ... fs) { return [...fs = std::forward(fs)](const auto& ... ts) { return (fs(ts...) && ...);         }; }; Fold expression for logical and of the result of each function, with short cirquiting

Slide 130

Slide 130 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 130/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto when_all = [](Fs&& ... fs) { return [...fs = std::forward(fs)](const auto& ... ts) { return (fs(ts...) && ...);         }; }; Note that we don’t want perfect forwarding of the ts...

Slide 131

Slide 131 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 131/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto when_all = [](Fs&& ... fs) { return [...fs = std::forward(fs)](const auto& ... ts) { return (fs(ts...) && ...);         }; }; We can now improve bind_back from earlier

Slide 132

Slide 132 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 132/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto when_all = [](Fs&& ... fs) { return [...fs = std::forward(fs)](const auto& ... ts) { return (fs(ts...) && ...);         }; }; auto bind_back = [](F&& f, Ts&& ... ts) { return [f = std::forward(f), ...ts=std::forward(ts)] (Vs&& ... vs) -> decltype(auto) { return f(std::forward(vs)..., ts...); }; }; We can now improve bind_back from earlier

Slide 133

Slide 133 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 133/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto with_state = [](auto state) { return compose(equals(state), get_state); }; void activate(std::span interfaces, ip_address addr, netmask mask) { auto to_activate = interfaces | std::ranges::views::filter( when_all(with_state(ipif::off),         with_address(addr, mask))); std::ranges::for_each(to_activate, set_state(ipif::on)); }

Slide 134

Slide 134 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 134/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto with_state = [](auto state) { return compose(equals(state), get_state); }; void activate(std::span interfaces, ip_address addr, netmask mask) { auto to_activate = interfaces | std::ranges::views::filter( when_all(with_state(ipif::off),         with_address(addr, mask))); std::ranges::for_each(to_activate, set_state(ipif::on)); } We now have the tools to do something really cool with our network interfaces!

Slide 135

Slide 135 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 135/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto with_state = [](auto state) { return compose(equals(state), get_state); }; void activate(std::span interfaces, ip_address addr, netmask mask) { auto to_activate = interfaces | std::ranges::views::filter( when_all(with_state(ipif::off),         with_address(addr, mask))); std::ranges::for_each(to_activate, set_state(ipif::on)); } We now have the tools to do something really cool with our network interfaces!

Slide 136

Slide 136 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 136/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto with_state = [](auto state) { return compose(equals(state), get_state); }; void activate(std::span interfaces, ip_address addr, netmask mask) { auto to_activate = interfaces | std::ranges::views::filter( when_all(with_state(ipif::off),         with_address(addr, mask))); std::ranges::for_each(to_activate, set_state(ipif::on)); } Get all interfaces that are off We now have the tools to do something really cool with our network interfaces!

Slide 137

Slide 137 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 137/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto with_state = [](auto state) { return compose(equals(state), get_state); }; void activate(std::span interfaces, ip_address addr, netmask mask) { auto to_activate = interfaces | std::ranges::views::filter( when_all(with_state(ipif::off),         with_address(addr, mask))); std::ranges::for_each(to_activate, set_state(ipif::on)); } ...and has a matching address We now have the tools to do something really cool with our network interfaces!

Slide 138

Slide 138 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 138/208 Network interfaces class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; auto with_state = [](auto state) { return compose(equals(state), get_state); }; void activate(std::span interfaces, ip_address addr, netmask mask) { auto to_activate = interfaces | std::ranges::views::filter( when_all(with_state(ipif::off),         with_address(addr, mask))); std::ranges::for_each(to_activate, set_state(ipif::on)); } Then set their state to on We now have the tools to do something really cool with our network interfaces!

Slide 139

Slide 139 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 139/208 https://godbolt.org/z/j1szzjcEv

Slide 140

Slide 140 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 140/208 std::optional Has become extraordinarily well suited for higher order functions from C++23

Slide 141

Slide 141 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 141/208 std::optional https://en.cppreference.com/w/cpp/utility/optional Has become extraordinarily well suited for higher order functions from C++23

Slide 142

Slide 142 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 142/208 std::optional https://en.cppreference.com/w/cpp/utility/optional Has become extraordinarily well suited for higher order functions from C++23 Calls a function(T) if the optional holds a value. The function must return an optional. If the optional did not hold a value .and_then() returns an empty optional

Slide 143

Slide 143 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 143/208 std::optional https://en.cppreference.com/w/cpp/utility/optional Has become extraordinarily well suited for higher order functions from C++23 Calls a function(T) if the optional holds a value. If the function returns a type U, then .transform() returns optional. If the optional did not hold a value, it returns an empty optional

Slide 144

Slide 144 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 144/208 std::optional https://en.cppreference.com/w/cpp/utility/optional Has become extraordinarily well suited for higher order functions from C++23 If the optional holds a value .or_else() returns the optional itself, otherwise it calls a function. The function must return an optional.

Slide 145

Slide 145 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 145/208 std::optional https://en.cppreference.com/w/cpp/utility/optional Has become extraordinarily well suited for higher order functions from C++23 T can not be a reference

Slide 146

Slide 146 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 146/208 std::optional https://en.cppreference.com/w/cpp/utility/optional Has become extraordinarily well suited for higher order functions from C++23 T can not be a reference You can work around that with std::reference_wrapper

Slide 147

Slide 147 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 147/208 std::optional https://en.cppreference.com/w/cpp/utility/optional Has become extraordinarily well suited for higher order functions from C++23 T can not be a reference You can work around that with std::reference_wrapper T cannot be void

Slide 148

Slide 148 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 148/208 std::optional https://en.cppreference.com/w/cpp/utility/optional Has become extraordinarily well suited for higher order functions from C++23 T can not be a reference You can work around that with std::reference_wrapper T cannot be void There is no work around for that

Slide 149

Slide 149 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 149/208 std::optional https://en.cppreference.com/w/cpp/utility/optional Has become extraordinarily well suited for higher order functions from C++23 T can not be a reference You can work around that with std::reference_wrapper T cannot be void There is no work around for that What would optional mean if it were allowed?

Slide 150

Slide 150 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 150/208 std::optional https://en.cppreference.com/w/cpp/utility/optional Has become extraordinarily well suited for higher order functions from C++23 T can not be a reference You can work around that with std::reference_wrapper T cannot be void There is no work around for that What would optional mean if it were allowed? The function to .transform() must return something

Slide 151

Slide 151 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 151/208 std::optional class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; };

Slide 152

Slide 152 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 152/208 std::optional class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; Won’t work with .transform()

Slide 153

Slide 153 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 153/208 std::optional class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; state_type set_state(state_type);

Slide 154

Slide 154 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 154/208 std::optional class ipif { public: using state_type = enum { off, on }; void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; state_type set_state(state_type); But this will!

Slide 155

Slide 155 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 155/208 std::optional class ipif { public: using state_type = enum { off, on }; state_type set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; };

Slide 156

Slide 156 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 156/208 std::optional class ipif { public: using state_type = enum { off, on }; state_type set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; template std::optional> find_interface(std::span interfaces, Predicate pred) { if (auto it = std::ranges::find_if(interfaces, pred); it != interfaces.end()) { return *it; } return std::nullopt; }

Slide 157

Slide 157 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 157/208 std::optional class ipif { public: using state_type = enum { off, on }; state_type set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; template std::optional> find_interface(std::span interfaces, Predicate pred) { if (auto it = std::ranges::find_if(interfaces, pred); it != interfaces.end()) { return *it; } return std::nullopt; } Find an interface, given a predicate

Slide 158

Slide 158 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 158/208 std::optional class ipif { public: using state_type = enum { off, on }; state_type set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; template std::optional> find_interface(std::span interfaces, Predicate pred) { if (auto it = std::ranges::find_if(interfaces, pred); it != interfaces.end()) { return *it; } return std::nullopt; } Return a reference to it, if found, or std::nullopt otherwise

Slide 159

Slide 159 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 159/208 std::optional class ipif { public: using state_type = enum { off, on }; state_type set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; template std::optional> find_interface(std::span interfaces, Predicate pred) { if (auto it = std::ranges::find_if(interfaces, pred); it != interfaces.end()) { return *it; } return std::nullopt; } bool activate(std::span interfaces, ip_address addr) { return find_interface(interfaces, with_address(addr)) .transform(set_state(ipif::on)) .has_value(); }

Slide 160

Slide 160 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 160/208 std::optional class ipif { public: using state_type = enum { off, on }; state_type set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; template std::optional> find_interface(std::span interfaces, Predicate pred) { if (auto it = std::ranges::find_if(interfaces, pred); it != interfaces.end()) { return *it; } return std::nullopt; } bool activate(std::span interfaces, ip_address addr) { return find_interface(interfaces, with_address(addr)) .transform(set_state(ipif::on)) .has_value(); } Lookup the interface from its address

Slide 161

Slide 161 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 161/208 std::optional class ipif { public: using state_type = enum { off, on }; state_type set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; template std::optional> find_interface(std::span interfaces, Predicate pred) { if (auto it = std::ranges::find_if(interfaces, pred); it != interfaces.end()) { return *it; } return std::nullopt; } bool activate(std::span interfaces, ip_address addr) { return find_interface(interfaces, with_address(addr)) .transform(set_state(ipif::on)) .has_value(); } If it was found, set its state

Slide 162

Slide 162 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 162/208 std::optional class ipif { public: using state_type = enum { off, on }; state_type set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; template std::optional> find_interface(std::span interfaces, Predicate pred) { if (auto it = std::ranges::find_if(interfaces, pred); it != interfaces.end()) { return *it; } return std::nullopt; } bool activate(std::span interfaces, ip_address addr) { return find_interface(interfaces, with_address(addr)) .transform(set_state(ipif::on)) .has_value(); } Tell if it was found

Slide 163

Slide 163 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 163/208 std::optional class ipif { public: using state_type = enum { off, on }; state_type set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; template std::optional> find_interface(std::span interfaces, Predicate pred) { if (auto it = std::ranges::find_if(interfaces, pred); it != interfaces.end()) { return *it; } return std::nullopt; } bool activate(std::span interfaces, ip_address addr) { return find_interface(interfaces, with_address(addr)) .transform(set_state(ipif::on)) .has_value(); }

Slide 164

Slide 164 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 164/208 https://godbolt.org/z/4vW8Gb9e9

Slide 165

Slide 165 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 165/208 deducing this

Slide 166

Slide 166 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 166/208 deducing this A small new C++23 feature with huge impact

Slide 167

Slide 167 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 167/208 deducing this A small new C++23 feature with huge impact There will be several conference talks about this feature alone

Slide 168

Slide 168 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 168/208 deducing this A small new C++23 feature with huge impact There will be several conference talks about this feature alone Currently available in MSVC and in clang-main (but not in any released version). Not yet available in gcc.

Slide 169

Slide 169 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 169/208 deducing this A small new C++23 feature with huge impact There will be several conference talks about this feature alone Currently available in MSVC and in clang-main (but not in any released version). Not yet available in gcc. Thanks Corentin

Slide 170

Slide 170 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 170/208 deducing this A small new C++23 feature with huge impact There will be several conference talks about this feature alone Currently available in MSVC and in clang-main (but not in any released version). Not yet available in gcc. Allows you to know the qualification of the object that a function was called in, by making “this” an explicit template parameter.

Slide 171

Slide 171 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 171/208 deducing this A small new C++23 feature with huge impact There will be several conference talks about this feature alone Currently available in MSVC and in clang-main (but not in any released version). Not yet available in gcc. Allows you to know the qualification of the object that a function was called in, by making “this” an explicit template parameter. A good companion with new library utility std::forward_like(u)

Slide 172

Slide 172 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 172/208 deducing this auto f = [](this Self&&, int) { if constexpr (std::is_const_v>) {   std::cout << "const "; } if constexpr (std::is_lvalue_reference_v) { std::cout << "&"; } else { std::cout << "&&"; } std::cout << '\n'; };

Slide 173

Slide 173 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 173/208 deducing this auto f = [](this Self&&, int) { if constexpr (std::is_const_v>) {   std::cout << "const "; } if constexpr (std::is_lvalue_reference_v) { std::cout << "&"; } else { std::cout << "&&"; } std::cout << '\n'; }; New syntax to make the this parameter explicit.

Slide 174

Slide 174 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 174/208 deducing this auto f = [](this Self&&, int) { if constexpr (std::is_const_v>) {   std::cout << "const "; } if constexpr (std::is_lvalue_reference_v) { std::cout << "&"; } else { std::cout << "&&"; } std::cout << '\n'; };

Slide 175

Slide 175 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 175/208 deducing this auto f = [](this Self&&, int) { if constexpr (std::is_const_v>) {   std::cout << "const "; } if constexpr (std::is_lvalue_reference_v) { std::cout << "&"; } else { std::cout << "&&"; } std::cout << '\n'; }; f(3); std::as_const(f)(5); std::move(f)(8); std::move(std::as_const(f))(13);

Slide 176

Slide 176 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 176/208 deducing this auto f = [](this Self&&, int) { if constexpr (std::is_const_v>) {   std::cout << "const "; } if constexpr (std::is_lvalue_reference_v) { std::cout << "&"; } else { std::cout << "&&"; } std::cout << '\n'; }; f(3); std::as_const(f)(5); std::move(f)(8); std::move(std::as_const(f))(13); &

Slide 177

Slide 177 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 177/208 deducing this auto f = [](this Self&&, int) { if constexpr (std::is_const_v>) {   std::cout << "const "; } if constexpr (std::is_lvalue_reference_v) { std::cout << "&"; } else { std::cout << "&&"; } std::cout << '\n'; }; f(3); std::as_const(f)(5); std::move(f)(8); std::move(std::as_const(f))(13); & const &

Slide 178

Slide 178 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 178/208 deducing this auto f = [](this Self&&, int) { if constexpr (std::is_const_v>) {   std::cout << "const "; } if constexpr (std::is_lvalue_reference_v) { std::cout << "&"; } else { std::cout << "&&"; } std::cout << '\n'; }; f(3); std::as_const(f)(5); std::move(f)(8); std::move(std::as_const(f))(13); & const & &&

Slide 179

Slide 179 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 179/208 deducing this auto f = [](this Self&&, int) { if constexpr (std::is_const_v>) {   std::cout << "const "; } if constexpr (std::is_lvalue_reference_v) { std::cout << "&"; } else { std::cout << "&&"; } std::cout << '\n'; }; f(3); std::as_const(f)(5); std::move(f)(8); std::move(std::as_const(f))(13); & const & && const &&

Slide 180

Slide 180 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 180/208 deducing this auto f = [](this Self&&, int) { if constexpr (std::is_const_v>) {   std::cout << "const "; } if constexpr (std::is_lvalue_reference_v) { std::cout << "&"; } else { std::cout << "&&"; } std::cout << '\n'; }; f(3); std::as_const(f)(5); std::move(f)(8); std::move(std::as_const(f))(13); & const & && const &&

Slide 181

Slide 181 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 181/208 deducing this auto f = [](this Self&&, int) { if constexpr (std::is_const_v>) {   std::cout << "const "; } if constexpr (std::is_lvalue_reference_v) { std::cout << "&"; } else { std::cout << "&&"; } std::cout << '\n'; }; f(3); std::as_const(f)(5); std::move(f)(8); std::move(std::as_const(f))(13); & const & && const &&

Slide 182

Slide 182 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 182/208 deducing this auto f = [](this Self&&, int) { if constexpr (std::is_const_v>) {   std::cout << "const "; } if constexpr (std::is_lvalue_reference_v) { std::cout << "&"; } else { std::cout << "&&"; } std::cout << '\n'; }; f(3); std::as_const(f)(5); std::move(f)(8); std::move(std::as_const(f))(13); & const & && const &&

Slide 183

Slide 183 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 183/208 Fixing bind_back auto bind_back = [](F&& f, Ts&& ... ts) { return [f = std::forward(f), ...ts=std::forward(ts)] (this Self&&, Vs&& ... vs) -> decltype(auto) { return std::forward_like(f)( std::forward(vs)..., std::forward_like(ts)… );         }; };

Slide 184

Slide 184 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 184/208 Fixing bind_back auto bind_back = [](F&& f, Ts&& ... ts) { return [f = std::forward(f), ...ts=std::forward(ts)] (this Self&&, Vs&& ... vs) -> decltype(auto) { return std::forward_like(f)( std::forward(vs)..., std::forward_like(ts)… );         }; }; Learn if we’re called as an lvalue or rvalue, const or not, etc.

Slide 185

Slide 185 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 185/208 Fixing bind_back auto bind_back = [](F&& f, Ts&& ... ts) { return [f = std::forward(f), ...ts=std::forward(ts)] (this Self&&, Vs&& ... vs) -> decltype(auto) { return std::forward_like(f)( std::forward(vs)..., std::forward_like(ts)… );         }; }; Move the captured function if the lambda is called as an rvalue, otherwise use as lvalue.

Slide 186

Slide 186 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 186/208 Fixing bind_back auto bind_back = [](F&& f, Ts&& ... ts) { return [f = std::forward(f), ...ts=std::forward(ts)] (this Self&&, Vs&& ... vs) -> decltype(auto) { return std::forward_like(f)( std::forward(vs)..., std::forward_like(ts)… );         }; }; Forward the direct function call parameters as before.

Slide 187

Slide 187 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 187/208 Fixing bind_back auto bind_back = [](F&& f, Ts&& ... ts) { return [f = std::forward(f), ...ts=std::forward(ts)] (this Self&&, Vs&& ... vs) -> decltype(auto) { return std::forward_like(f)( std::forward(vs)..., std::forward_like(ts)… );         }; }; Move the captured values if the lambda is an rvalue, otherwise pass as lvalue-references

Slide 188

Slide 188 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 188/208 Fixing bind_back auto bind_back = [](F&& f, Ts&& ... ts) { return [f = std::forward(f), ...ts=std::forward(ts)] (this Self&&, Vs&& ... vs) -> decltype(auto) { return std::forward_like(f)( std::forward(vs)..., std::forward_like(ts)… );         }; }; Now bind_back can safely be used with types like std::unique_ptr<>, which will only be moved if called with an rvalue.

Slide 189

Slide 189 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 189/208 https://godbolt.org/z/vf13Y961W

Slide 190

Slide 190 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 190/208 curry https://en.wikipedia.org/wiki/Currying

Slide 191

Slide 191 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 191/208 curry auto curry = [](this auto& curry, F&& f) { return    [&curry, f = std::forward(f)] ( auto ... ts) -> decltype(auto) { if constexpr (requires { f ( ts ...); }) { return f ( ts ...); } else { return curry(std::bind_front( f , ts ...)); } }; };

Slide 192

Slide 192 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 192/208 curry auto curry = [](this auto& curry, F&& f) { return    [&curry, f = std::forward(f)] ( auto ... ts) -> decltype(auto) { if constexpr (requires { f ( ts ...); }) { return f ( ts ...); } else { return curry(std::bind_front( f , ts ...)); } }; }; Lambda deducing itself as a reference

Slide 193

Slide 193 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 193/208 curry auto curry = [](this auto& curry, F&& f) { return    [&curry, f = std::forward(f)] ( auto ... ts) -> decltype(auto) { if constexpr (requires { f ( ts ...); }) { return f ( ts ...); } else { return curry(std::bind_front( f , ts ...)); } }; }; Lambda deducing itself as a reference So it can call itself recursively

Slide 194

Slide 194 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 194/208 curry auto curry = [](this auto& curry, F&& f) { return    [&curry, f = std::forward(f)] ( auto ... ts) -> decltype(auto) { if constexpr (requires { f ( ts ...); }) { return f ( ts ...); } else { return curry(std::bind_front( f , ts ...)); } }; }; The call is made if it can be

Slide 195

Slide 195 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 195/208 curry auto curry = [](this auto& curry, F&& f) { return    [&curry, f = std::forward(f)] ( auto ... ts) -> decltype(auto) { if constexpr (requires { f ( ts ...); }) { return f ( ts ...); } else { return curry(std::bind_front( f , ts ...)); } }; }; Otherwise bind the arguments and curry the tail

Slide 196

Slide 196 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 196/208 curry auto curry = [](this auto& curry, F&& f) { return    [&curry, f = std::forward(f)] (this Self&&, auto ... ts) -> decltype(auto) { if constexpr (requires { std::forward_like(f)( ts ...); }) { return std::forward_like(f)( ts ...); } else { return curry(std::bind_front(std::forward_like(f), ts ...)); } }; };

Slide 197

Slide 197 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 197/208 curry auto curry = [](this auto& curry, F&& f) { return    [&curry, f = std::forward(f)] (this Self&&, auto ... ts) -> decltype(auto) { if constexpr (requires { std::forward_like(f)( ts ...); }) { return std::forward_like(f)( ts ...); } else { return curry(std::bind_front(std::forward_like(f), ts ...)); } }; }; Now deduce the type of the inner lambda

Slide 198

Slide 198 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 198/208 curry auto curry = [](this auto& curry, F&& f) { return    [&curry, f = std::forward(f)] (this Self&&, auto ... ts) -> decltype(auto) { if constexpr (requires { std::forward_like(f)( ts ...); }) { return std::forward_like(f)( ts ...); } else { return curry(std::bind_front(std::forward_like(f), ts ...)); } }; }; So the bound function can be called as r/l- value So the bound function can be called as r/l- value So the bound function can be called as r/l- value

Slide 199

Slide 199 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 199/208 curry auto curry = [](this auto& curry, F&& f) { return    [&curry, f = std::forward(f)] (this Self&&, Ts&& ... ts) -> decltype(auto) { if constexpr (requires { std::forward_like(f)(std::forward(ts)...); }) { return std::forward_like(f)(std::forward(ts)...); } else { return curry(std::bind_front(std::forward_like(f), std::forward(ts)...)); } }; };

Slide 200

Slide 200 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 200/208 curry auto curry = [](this auto& curry, F&& f) { return    [&curry, f = std::forward(f)] (this Self&&, Ts&& ... ts) -> decltype(auto) { if constexpr (requires { std::forward_like(f)(std::forward(ts)...); }) { return std::forward_like(f)(std::forward(ts)...); } else { return curry(std::bind_front(std::forward_like(f), std::forward(ts)...)); } }; }; Lambda deducing itself as a reference Perfect forwarding of the arguments Perfect forwarding of the arguments Perfect forwarding of the arguments

Slide 201

Slide 201 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 201/208 https://godbolt.org/z/xjTehGs45

Slide 202

Slide 202 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 202/208 Summary

Slide 203

Slide 203 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 203/208 Summary ● Higher order functions in general, and function composition in particular, is powerful!

Slide 204

Slide 204 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 204/208 Summary ● Higher order functions in general, and function composition in particular, is powerful! ● They are very suitable for new library features like ranges and the new functionality of optional and expected

Slide 205

Slide 205 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 205/208 Summary ● Higher order functions in general, and function composition in particular, is powerful! ● They are very suitable for new library features like ranges and the new functionality of optional and expected ● New language features like variadic lambda capture makes life easier

Slide 206

Slide 206 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 206/208 Summary ● Higher order functions in general, and function composition in particular, is powerful! ● They are very suitable for new library features like ranges and the new functionality of optional and expected ● New language features like variadic lambda capture makes life easier ● “deducing this” is a new super power!

Slide 207

Slide 207 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 207/208 Summary ● Higher order functions in general, and function composition in particular, is powerful! ● They are very suitable for new library features like ranges and the new functionality of optional and expected ● New language features like variadic lambda capture makes life easier ● “deducing this” is a new super power! – https://devblogs.microsoft.com/cppblog/cpp23-deducing-this/

Slide 208

Slide 208 text

Function Moar with C++23 – MUC++ 2023 © Björn Fahller @[email protected] 208/208 Björn Fahller Function Moar with C++23 [email protected] @[email protected] @rollbear Björn Fahller