Lambdas uses and abuses github.com/zaldawid Dawid Zalewski - - PowerPoint PPT Presentation

lambdas uses and abuses
SMART_READER_LITE
LIVE PREVIEW

Lambdas uses and abuses github.com/zaldawid Dawid Zalewski - - PowerPoint PPT Presentation

Lambdas uses and abuses github.com/zaldawid Dawid Zalewski zaldawid@gmail.com 15-Nov-20 @zaldawid auto forty_two = 42; std::vector functions = { [forty_two](){ return forty_two; }, [](auto denominator){ return 1.0 / denominator; },


slide-1
SLIDE 1

Lambdas – uses and abuses

Dawid Zalewski

15-Nov-20

github.com/zaldawid zaldawid@gmail.com @zaldawid

slide-2
SLIDE 2

Dawid Zalewski

auto forty_two = 42; std::vector functions = { [forty_two](){ return forty_two; }, [](auto denominator){ return 1.0 / denominator; }, [](auto a, auto b){ return a + b; } }; error: class template argument deduction failed

15-Nov-20 2 Lambdas, uses and abuses

slide-3
SLIDE 3

Dawid Zalewski

auto forty_two = 42; std::vector functions = { [](int a, int b){ return a + b; }, [](int a, int b){ return a - b; }, [](int a, int b){ return a * b; }, }; error: class template argument deduction failed

15-Nov-20 3 Lambdas, uses and abuses

slide-4
SLIDE 4

Dawid Zalewski

auto forty_two = 42; container_t functions = { [forty_two](){ return forty_two; }, [](auto denominator){ return 1.0 / denominator; }, [](auto a, auto b){ return a + b; } }; auto answer = functions.call(); auto reciprocal = functions.call(42); auto sum = functions.call(4, 2);

15-Nov-20 4 Lambdas, uses and abuses

slide-5
SLIDE 5

Dawid Zalewski

Lambdas’ anatomy

15-Nov-20 Lambdas, uses and abuses 5

Common ground Latest and greatest Inheritance trick Uses and abuses

[cnt] <typename T> (T a, T b) mutable { while (cnt--) a+=b; return a; }

lambda introducer (capture list) lambda declarator (params & specifiers) compound statement (lambda body) template params (c++20 only) lambda params specifiers

slide-6
SLIDE 6

Dawid Zalewski

class lmb_t{ public: inline constexpr auto

  • perator()(int x, int y) const {

return x + y; } lmb_t() = default; }; auto lmb = lmb_t();

Closures

auto lmb = [](int x, int y) { return x + y; };

15-Nov-20 Lambdas, uses and abuses 6

Lambda expression Closure type

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-7
SLIDE 7

Dawid Zalewski

Closures with function templates

auto lmb = [](auto x, auto y) { return x + y; }; class lmb_t{ public: template <typename T1, typename T2> inline constexpr auto

  • perator()(T1 x, T2 y) const {

return x + y; } lmb_t() = default; }; auto lmb = lmb_t();

15-Nov-20 Lambdas, uses and abuses 7

Lambda expression Closure type

‘I ‘Invented’ ’ types

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-8
SLIDE 8

Dawid Zalewski

Closures with concepts

auto lmb = [] <std::integral T> (T x, T y) { return x + y; }; class lmb_t{ public: template <std::integral T> inline constexpr auto

  • perator()(T x, T y) const {

return x + y; } lmb_t() = default; }; auto lmb = lmb_t();

15-Nov-20 Lambdas, uses and abuses 8

Lambda expression Closure type

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-9
SLIDE 9

Dawid Zalewski

class lmb1_t{ public: int operator()() const { return k += 11; } private: int k; } auto lmb1 = lmb1_t(k); void func(){ auto k = 42; auto lmb1 = [=] () { return k += 11; }; return lmb1(); }

Closures: member variables

15-Nov-20 Lambdas, uses and abuses 9

error: assignment of read-only variable 'k'

Lambda expression Closure type

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-10
SLIDE 10

Dawid Zalewski

void func(){ auto k = 42; auto lmb2 = [=] () mutable { return k += 11; }; return lmb2(); } class lmb2_t{ public: int operator()() { return k += 11; } private: int k; }; auto lmb2 = lmb2(k);

Closures: member variables

15-Nov-20 Lambdas, uses and abuses 10

Lambda expression Closure type

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-11
SLIDE 11

Dawid Zalewski

Lambdas before C++20

15-Nov-20 Lambdas, uses and abuses 11

  • Limited generic types (no template <typename…>)
  • Lambdas are not default-constructible
  • Lambdas cannot appear in unevaluated context
  • No pack expansion in init capture
  • No capturing of structured bindings
  • Weirdness around captures in member functions
  • No self-referencing (recursive) lambdas

[p0428] [p0624] [p0315] [p0780] [p1091] [p0806, p0409] [p0839]

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-12
SLIDE 12

Dawid Zalewski

Generic lambdas with implicit invented types are no fun:

std::vector<double> v; push_one(v); auto push_one = [](auto& v){ using T = typename std::remove_reference_t<decltype(v)>::value_type; value_factory<T> f; v.push_back( f.get() ); };

Lambdas in C++20: templates

15-Nov-20 12 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-13
SLIDE 13

Dawid Zalewski

Explicit templates remove the boilerplate code:

std::vector<double> v; push_one(v); auto push_one = [] <typename T> (std::vector<T>& v){ value_factory<T> f; v.push_back( f.get() ); };

Lambdas in C++20: templates

15-Nov-20 13 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-14
SLIDE 14

Dawid Zalewski

Lambdas in C++20: templates++

#include <concepts> auto sum = [] <std::integral T> (T a, T b) { return a + b; }; auto sum = [] (T a, T b) requires std::integral<T> { return a + b; }; sum(21.0, 21.0); error:(…) candidate template ignored: constraints not satisfied with T = double] because 'double' does not satisfy 'Integral'

15-Nov-20 14 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-15
SLIDE 15

Dawid Zalewski

struct Process { int priority; }; using Container = std::vector<Process>; using ProcessOrdering = decltype( [](auto&& lhs, auto&& rhs){ return lhs.priority > rhs.priority; } ); std::priority_queue< Process, Container, ProcessOrdering > queue; … auto ordering = ProcessOrdering();

Lambdas in C++20: unevaluated & def-constructible

15-Nov-20 15

On Only for capture-less lamb mbdas!

Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-16
SLIDE 16

Dawid Zalewski

Lambdas in C++20: init capture pack expansion

template<class F, class... Args> auto make_task(F&& f, Args&&... args) { return [f = std::forward<F>(f), args...]() mutable { return std::forward<F>(f)(std::forward<Args>(args)...); }; } auto f = [](const auto& ... s) {((std::cout << s) ,...);}; auto task = make_task(f, std::string("bob")); task();

15-Nov-20 16

ta task closure Unne Unnecessary c y copy

Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-17
SLIDE 17

Dawid Zalewski

Lambdas in C++20: init capture pack expansion

template<class F, class... Args> auto make_task(F&& f, Args&&... args) { return [f = std::forward<F>(f), ...args=std::forward<Args>(args)]() mutable { return std::forward<F>(f)(std::forward<Args>(args)...); }; } auto f = [](const auto&& ... s) {((std::cout << s) ,...);}; auto task = make_task(f, std::string("bob"));

15-Nov-20 17

ta task closure In Init it-captures with pack expansions help avoidi ding copies.

Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-18
SLIDE 18

Dawid Zalewski

Let’s build a recursive lambda:

auto sum = [](int n) { return n == 0? 0 : n + sum(n-1); }; >> error: use of 'sum' before deduction of 'auto' auto sum = [](int n) { return n == 0? 0 : n + operator()(n-1); }; >> error: use of undeclared 'operator()'

Lambdas in C++20: recursive lambdas

15-Nov-20 18 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-19
SLIDE 19

Dawid Zalewski

Function pointers to the rescue?

int (*sum)(int) = [](int n) { return n == 0? 0 : n + sum(n-1); }; >> error: 'sum' is not captured int (*sum)(int) = [&](int n) { return n == 0? 0 : n + sum(n-1); }; >> error: cannot convert '<lambda>' to 'int (*)(int)' in initialization std::function<int(int)> sum = [&](int n) { return n == 0? 0 : n + sum(n-1); }; >> but std::function, really?

Lambdas in C++20: recursive lambdas

15-Nov-20 19 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-20
SLIDE 20

Dawid Zalewski

Add another lever of indirection:

auto sum = [](auto n){ auto sum_impl = [](auto&& self, auto n){ if (n == 0) return 0; return n + self(self, n - 1); }; return sum_impl(sum_impl, n); }; sum(42); //903

Lambdas applied: recursive lambdas (1)

15-Nov-20 20 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-21
SLIDE 21

Dawid Zalewski

Use the magic:

auto sum_ = [](auto&& sum, auto n) -> int { return n == 0? 0 : sum(n-1) + n; }; auto sum = magic_something{std::move(sum_)}; auto value = sum(42);

Lambdas applied: recursive lambdas (2)

15-Nov-20 21 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-22
SLIDE 22

Dawid Zalewski

Use the magic: a higher-order function (Y-combinator):

template <typename F> struct recurse { F func; template <typename... Args> decltype(auto) operator()(Args&&... args) const { return func(*this, std::forward<Args>(args)...); } }; auto sum_ = [](auto&& sum, auto n) -> int { return n == 0? 0 : sum(n-1) + n; }; auto sum = recurse{std::move(sum_)};

Lambdas applied: recursive lambdas (3)

15-Nov-20 22

Ag Aggregate te initi tializati tion Calls the lambda da Ca Calls re

recurs rse::opera rator( r()

Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-23
SLIDE 23

Dawid Zalewski

Use the magic: a higher-order function (Y-combinator):

template <typename F> struct recurse { F func; template <typename... Args> decltype(auto) operator()(Args&&... args) const { return func(*this, std::forward<Args>(args)...); } }; template <typename F> recurse(F) -> recurse<F>;

Lambdas applied: recursive lambdas (3)

15-Nov-20 23 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-24
SLIDE 24

Dawid Zalewski

Composing through inheritance

template <typename F> struct recurse { F func; template <typename... Args> decltype(auto) operator()(Args&&... args) const { return func(*this, std::forward<Args>(args)...); } }; template <typename F> recurse(F) -> recurse<F>; auto sum = recurse{std::move(sum_)};

Recursive lambdas: better composition

15-Nov-20 24

struct recurse : F { return F::operator()(*this, std::forward<Args>(args)...);

Ag Aggregate te initi tializati tion st still wor

  • rks!

s!*

*E *Eac ach dir irect public ic base (F) ) is co copy-in init itia ializ ized from the corresponding g lambda in the list.

Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

Inheriting from m a lamb mbda

slide-25
SLIDE 25

Dawid Zalewski

Lambdas applied: initializers

Default function arguments

void print_number(int number = [](auto n){ auto sum = n; while(n--) sum += n; return sum;}(42) ){ std::cout << number; }

15-Nov-20 25 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-26
SLIDE 26

Dawid Zalewski

Complex initialization using a function

auto x = 42; auto x = log_init("init x with: ", 42); template <typename Arg> decltype(auto) log_init(std::string_view msg, Arg&& arg){ std::cout << msg << arg; return std::forward<Arg>(arg); }

Lambdas applied: initializers

15-Nov-20 26 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-27
SLIDE 27

Dawid Zalewski

Re-usable & composable initialization: inheritance?

std::ofstream flog{"log.out"}; log_init_t log_init{ [fout=std::move(flog)](auto msg, auto&& value) mutable { fout << msg << value; }, [](auto msg, auto&& value){ std::cout << msg << value; } }; auto x = 42; auto x = log_init("init x with: ", 42);

Lambdas applied: initializers

15-Nov-20 27 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-28
SLIDE 28

Dawid Zalewski

Composing through multiple inheritance

template <typename F> struct log_init_t : F { template <typename Arg> decltype(auto) operator()(std::string_view msg, Arg&& arg){ F::operator()(msg, arg); return std::forward<Arg>(arg); } }; Fs... -> {Fs1, Fs2, Fs3} Fs1::operator()(msg, arg), Fs2::operator()(msg, arg), Fs3::operator()(msg, arg); (Fs::operator()(msg, arg),...);

Lambdas applied: initializers

15-Nov-20 Lambdas, uses and abuses 28

template <typename...Fs> struct log_init_t : Fs...{

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-29
SLIDE 29

Dawid Zalewski

Composing through multiple inheritance

template <typename...Fs> struct log_init_t : Fs...{ template <typename Arg> decltype(auto) operator()(std::string_view msg, Arg&& arg){ (Fs::operator()(msg, arg),...); return std::forward<Arg>(arg); } }; template <typename...Fs> log_init_t(Fs...) -> log_init_t<Fs...>;

Lambdas applied: initializers

15-Nov-20 Lambdas, uses and abuses 29

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-30
SLIDE 30

Dawid Zalewski

C++20 lambdas can do the same:

template <typename...Fs> decltype(auto) mk_loginit(Fs&&...fs){ return [...fs=std::forward<Fs>(fs)]<typename Arg>(auto msg, Arg&& arg) mutable { (fs(msg, arg),...); return std::forward<Arg>(arg); }; } auto log_init = mk_loginit( [fout=std::move(flog)](auto msg, auto&& value) mutable { fout << msg << value; }, [](auto msg, auto&& value){ std::cout << msg << value; } );

Lambdas applied: initializers

15-Nov-20 30 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-31
SLIDE 31

Dawid Zalewski

Lambdas applied: wrappers

When just lambdas aren’t enough:

auto logger = [](const auto& msg) { std::cout << msg; }; logger << "alice" << 42; logger{[](const auto& msg) { std::cout << msg; }} << "alice" << 42;

15-Nov-20 31 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-32
SLIDE 32

Dawid Zalewski

Lambdas applied: wrappers

Lambdas used as building blocks for a composition / adapter

std::ofstream fout{"out.txt"}; logger{ [](const auto& msg){ std::cout << msg; } [fout=std::move(fout)](const auto& msg) mutable { fout << msg; }, } << "alice" << 42;

15-Nov-20 32 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-33
SLIDE 33

Dawid Zalewski

Lambdas used as building blocks for an adapter

logger{/*lambdas*/} << "alice" << 42; template <typename...Fs> struct logger: Fs...{ template <typename T> logger& operator<<(const T& arg){ (Fs::operator()(arg),...); return *this; } }; template <typename...Fs> logger(Fs...) -> logger<Fs...>;

Lamdas applied: multiple inheritance

15-Nov-20 33 Lambdas, uses and abuses

Re Returning *t *this to to ena nable chained me method calls.

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-34
SLIDE 34

Dawid Zalewski

Chain of responsibility

15-Nov-20 Lambdas, uses and abuses 34

void accept(Data); void accept(Data); void accept(Data);

Ch Chain of respo ponsibili lity

data

ha handler er_1 ha handler er_2 ha handler er_3

But this look like the chain of responsibility design pattern!

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-35
SLIDE 35

Dawid Zalewski

Chain of responsibility: multiple loggers

A typical chain of responsibility

enum severity : int { info = 0, warn, error }; auto info_logger = [](severity s, auto msg){ if (s >= info) { /*handle logging*/ }}; auto warn_logger = [](severity s, auto msg){ if (s >= warn) { /*handle logging*/ }}; auto rc = resp_chain{info_logger, warn_logger}; … rc(info, "System started"); // only info_logger should log rc(warning, "Voltage too low (4.2)"); // only warn_logger should log

15-Nov-20 35 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-36
SLIDE 36

Dawid Zalewski

Chain of responsibility: multiple loggers

A typical chain of responsibility

template<typename...Fs> struct resp_chain : Fs... { template<typename...Args> void operator()(const Args&...args) { ((Fs::operator()(args...)), ...); } }; template<typename...Fs> resp_chain(Fs...) -> resp_chain<Fs...>;

15-Nov-20 36 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-37
SLIDE 37

Dawid Zalewski

Chain of responsibility: the canonical version

15-Nov-20 Lambdas, uses and abuses 37

bool accept(Data); bool accept(Data); bool accept(Data);

Ch Chain of respo ponsibili lity

data

ha handler er_1 ha handler er_2 ha handler er_3

T T T F F F

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-38
SLIDE 38

Dawid Zalewski

Chain of responsibility: the canonical version

Forwarding only if not handled

auto info_logger = [](severity s, auto msg){ if (s == info) { /*handle logging*/ return true; } return false; }; auto warn_logger = [](severity s, auto msg){ if (s == warn) { /*handle logging*/ return true; } return false; }; auto rc = resp_chain{info_logger, warn_logger}; … rc(info, "System started"); rc(warning, "Voltage too low (4.2)");

15-Nov-20 38 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-39
SLIDE 39

Dawid Zalewski

Chain of responsibility: the canonical version

Folding lambda parameter pack over binary or.

template<typename...Fs> struct resp_chain : Fs... { template<typename...Args> void operator()(const Args&...args) { ((Fs::operator()(args...)) || ...); } };

15-Nov-20 39 Lambdas, uses and abuses

Unary right fold d of Fs Fs… ove

  • ver

r || || We could d return th the result t here

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-40
SLIDE 40

Dawid Zalewski

Chain of responsibility: the canonical version

Folding lambda parameter pack over binary or.

template<typename...Fs> struct resp_chain : Fs... { template<typename...Args> decltype(auto) operator()(const Args&...args) { return ((Fs::operator()(args...)) || ...); } }; template<typename...Fs> resp_chain(Fs...) -> resp_chain<Fs...>;

15-Nov-20 40 Lambdas, uses and abuses

Unary right fold d of Fs Fs… ove

  • ver

r || ||

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-41
SLIDE 41

Dawid Zalewski

Chain of responsibility with optionals

Returning std::optional instead of bool complicates things…

struct log_entry{}; auto info_logger = [](severity s, auto msg) -> std::optional<log_entry> { if (s == info) { /*handle logging*/ return std::optional(log_entry{…}); } return std::nullopt; }; auto warn_logger = [](severity s, auto msg) -> std::optional<log_entry> { if (s == warn) { /*handle logging*/ return std::optional(log_entry{…}); } return std::nullopt; }; auto log_1 = rc(info, "System started"); auto log_2 = rc(error, "Low memory");

15-Nov-20 41 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-42
SLIDE 42

Dawid Zalewski

Returning std::optional instead of bool complicates things…

template<typename ... Fs> struct resp_chain : Fs... { template<typename...Args> decltype(auto) operator()(const Args&...args) { auto res{F::operator()(args...)}; ((res) || (( res = std::move(Fs::operator()(args...))) || ...)); return res; } };

Chain of responsibility with optionals

15-Nov-20 42 Lambdas, uses and abuses

template<typename F, typename ... Fs> struct resp_chain : F, Fs... {

Binary left fold d of Fs Fs… ove

  • ver

r || ||

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-43
SLIDE 43

Dawid Zalewski

Fizz-buzz

All of the sudden fizz-buzz becomes a child’s play

auto fizz_buzz = resp_chain{ [](auto n) { return n % 15 == 0 ? std::optional("FizzBuzz") : std::nullopt; }, [](auto n) { return n % 3 == 0 ? std::optional("Fizz") : std::nullopt; }, [](auto n) { return n % 5 == 0 ? std::optional("Buzz") : std::nullopt; }, [](auto n) { return std::optional(itoa(n)); } }; auto number = 0; while (number++ != 100) { std::cout << number << ": " << *fizz_buzz(number) << "\n"; }

15-Nov-20 43 Lambdas, uses and abuses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-44
SLIDE 44

Dawid Zalewski

An ugly case…

Global state variable and side effects

auto _handled{false}; void set_handled(); bool is_handled(); auto info_logger = [](severity s, auto msg) { if (s == info) { /*handle logging*/ set_handled(); } }; auto warn_logger = [](severity s, auto msg){ if (s == warn) { /*handle logging*/ set_handled(); } };

15-Nov-20 Lambdas, uses and abuses 44

Gl Global st state Side de ef effec ects

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-45
SLIDE 45

Dawid Zalewski

An ugly case: inheriting from (deeper) self

Recursion + primary class template

template<typename F, typename ... Fs> struct resp_chain : F, resp_chain<Fs...> { template <typename SF, typename...Args> void operator()(SF& sf, const Args&...args){ if (F::operator()(args...); !sf()){ resp_chain<Fs...>::operator()(sf, args...); } } };

15-Nov-20 Lambdas, uses and abuses 45

struct resp_chain : F, Fs... { bool is_handled();

Common ground Latest and greatest Inheritance trick Uses and abuses

Re Recursi sive ve call to

  • th

the rest t of th the chain

slide-46
SLIDE 46

Dawid Zalewski

An ugly case: inheriting from (deeper) self

Specialization for the final case

template<typename F> struct resp_chain<F> : F { template <typename SF, typename...Args> void operator()(SF&, const Args&...args) { F::operator()(args...); } }; template<typename... Fs> resp_chain(Fs...) -> resp_chain<Fs...>;

15-Nov-20 Lambdas, uses and abuses 46

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-47
SLIDE 47

Dawid Zalewski

All the inheritance on one slide

template<typename F> struct lambdas : F {}; template<typename...Fs> struct lambdas : Fs... {}; template<typename F, typename...Fs> struct lambdas : F, Fs... {}; template<typename F, typename...Fs> struct lambdas : F, lambdas<Fs...> {};

15-Nov-20 Lambdas, uses and abuses 47

Simp mple cases Multiple lamb mbda’s Pa Pack ex expansion Fo Fold expressions For picking the result of the first lamb mbda Re Recursive calls

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-48
SLIDE 48

Dawid Zalewski

Adding new handlers to an existing chain

enum severity { info, warning, error }; auto info_logger = [](severity s, auto msg) { if (s == info) ...}; auto warn_logger = [](severity s, auto msg) { if (s == warn) ...}; auto rc = resp_chain{info_logger, warn_logger}; rc(error, "Low memory");

But there is more!

15-Nov-20 48 Lambdas, uses and abuses

Won’t be handl dled

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-49
SLIDE 49

Dawid Zalewski

Adding new handlers to an existing chain

auto rc = resp_chain{info_logger, warn_logger}; rc_with_error(error, "Low memory"); // won’t be handled auto err_logger = [](severity s, auto msg) -> std::optional<log_entry> { if (s == error){ /*handle logging*/ return std::optional(log_entry{…}); } return std::nullopt; }; auto rc_with_err = rc.set_next(std::move(err_logger); rc_with_error(error, "Low memory");

But there is more!

15-Nov-20 49 Lambdas, uses and abuses

Handl dled d by er err_logger gger

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-50
SLIDE 50

Dawid Zalewski

But there is more: programming with types

template<typename F, typename ... Fs> struct resp_chain : F, Fs ... { template<typename...Args> decltype(auto) operator()(Args&& ...args) { ... } template<typename G> decltype(auto) set_next(G&& g) { using G_ = std::remove_cvref_t<G>; return resp_chain<F, Fs..., G_>{*this, static_cast<Fs&>(*this)..., std::forward<G>(g)}; } };

15-Nov-20 Lambdas, uses and abuses 50

se set_next xt re return rns a a new ew ty type pe! Co Copy py-in init itia ialize ize ba base se cl classe sses

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-51
SLIDE 51

Dawid Zalewski

Uses and abuses

  • Folds + inheritance = composable lambdas
  • Clean, reusable abstractions
  • Strong types for safer code
  • Compile-time checks

15-Nov-20 Lambdas, uses and abuses 51

Common ground Latest and greatest Inheritance trick Uses and abuses

slide-52
SLIDE 52

Dawid Zalewski

Lambdas, uses & abuses

15-Nov-20 52

Dawid Zalewski github.com/zaldawid zaldawid@gmail.com @zaldawid

Lambdas, uses and abuses