Slide 1

Slide 1 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 1/127 Modern Techniques for Keeping Your Code DRY Björn Fahller

Slide 2

Slide 2 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 2/127 assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 3

Slide 3 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 3/127 assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 4

Slide 4 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 4/127 Modern Techniques for Keeping Your Code DRY Björn Fahller

Slide 5

Slide 5 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 5/127 Modern Techniques for Keeping Your Code DRY Björn Fahller

Slide 6

Slide 6 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 6/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 7

Slide 7 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 7/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED); variadic function template

Slide 8

Slide 8 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 8/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template bool is_any_of(state_type s, const Ts& ==. ts) { return ((s == ts) =| ==.); } assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 9

Slide 9 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 9/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template bool is_any_of(state_type s, const Ts& ==. ts) { return ((s == ts) =| ==.); } assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 10

Slide 10 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 10/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template bool is_any_of(state_type s, const Ts& ==. ts) { return ((s == ts) =| ==.); } assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 11

Slide 11 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 11/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template bool is_any_of(state_type s, const Ts& ==. ts) { return ((s == ts) =| ==.); } assert(is_any_of(state, IDLE, DISCONNECTING, DISCONNECTED));

Slide 12

Slide 12 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 12/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template bool is_any_of(state_type s, const Ts& ==. ts) { return ((s == ts) =| ==.); } assert(is_any_of(state, IDLE, DISCONNECTING, DISCONNECTED)); Utterly unreadable trash code!

Slide 13

Slide 13 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 13/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED); variadic non-type template parameter function template

Slide 14

Slide 14 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 14/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template bool is_any_of(state_type t) { return ((t == states) =| ==.); } assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 15

Slide 15 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 15/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template bool is_any_of(state_type t) { return ((t == states) =| ==.); } assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 16

Slide 16 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 16/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template bool is_any_of(state_type t) { return ((t == states) =| ==.); } assert(is_any_of(state));

Slide 17

Slide 17 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 17/127 auto for non-type template parameters from C++17 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template bool is_any_of(const T& t) { return ((t == alternatives) =| ==.); } assert(is_any_of(state));

Slide 18

Slide 18 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 18/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template bool is_any_of(const T& t) { return ((t == alternatives) =| ==.); } assert(is_any_of(state)); Not all types can be used as non-type template parameters Only constexpr values Yoda speak

Slide 19

Slide 19 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 19/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED); construct then test

Slide 20

Slide 20 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 20/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 21

Slide 21 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 21/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template auto is_in(const T& t) { return [t](const auto& ==. vs) { return ((t == vs) =| ==.); }; } assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 22

Slide 22 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 22/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template auto is_in(const T& t) { return [t](const auto& ==. vs) { return ((t == vs) =| ==.); }; } assert(is_in(state)(IDLE, DISCONNECTING, DISCONNECTED));

Slide 23

Slide 23 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 23/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template auto is_in(const T& t) { return [t](const auto& ==. vs) { return ((t == vs) =| ==.); }; } assert(is_in(state)(IDLE, DISCONNECTING, DISCONNECTED));

Slide 24

Slide 24 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 24/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template auto is_in(const T& t) { return [t](const auto& ==. vs) { return ((t == vs) =| ==.); }; } assert(is_in(state)(IDLE, DISCONNECTING, DISCONNECTED)); Works with all types Looks horrible Is a bit too terse

Slide 25

Slide 25 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 25/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED); explicit construct and compare function

Slide 26

Slide 26 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 26/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct is { T t; template bool any_of(const Ts& ==. ts) const { return ((t == ts) =| ==.); } }; template is(T) => is; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 27

Slide 27 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 27/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct is { T t; template bool any_of(const Ts& ==. ts) const { return ((t == ts) =| ==.); } }; template is(T) => is; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 28

Slide 28 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 28/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct is { T t; template bool any_of(const Ts& ==. ts) const { return ((t == ts) =| ==.); } }; template is(T) => is; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED); C++17 Deduction Guide for Constructor Template Argument Deduction

Slide 29

Slide 29 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 29/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct is { T t; template bool any_of(const Ts& ==. ts) const { return ((t == ts) =| ==.); } }; template is(T) => is; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED); C++17 Deduction Guide for Constructor Template Argument Deduction https://youtu.be/-H-ut6j1BYU https://youtu.be/UDs90b0yjjQ

Slide 30

Slide 30 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 30/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct is { T t; template bool any_of(const Ts& ==. ts) const { return ((t == ts) =| ==.); } }; template is(T) => is; assert(is{state}.any_of(IDLE, DISCONNECTING, DISCONNECTED)); Works with all types Explicit Still Yoda speak

Slide 31

Slide 31 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 31/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED); time passes...

Slide 32

Slide 32 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 32/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED); your mildly annoyed developer stays annoyed...

Slide 33

Slide 33 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 33/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED); Then one day, two years later!

Slide 34

Slide 34 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 34/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE =| state == DISCONNECTING =| state == DISCONNECTED);

Slide 35

Slide 35 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 35/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&… ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } }; template any_of(Ts==.) => any_of; assert(any_of(IDLE, DISCONNECTING, DISCONNECTED) == state);

Slide 36

Slide 36 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 36/127 Pure laziness, but these give me 18 constructors enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } }; template any_of(Ts==.) => any_of; assert(any_of(IDLE, DISCONNECTING, DISCONNECTED) == state);

Slide 37

Slide 37 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 37/127 Call function with each member of the tuple as a parameter. enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } }; template any_of(Ts==.) => any_of; assert(state == any_of(IDLE, DISCONNECTING, DISCONNECTED));

Slide 38

Slide 38 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 38/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } template friend bool operator==(const T& lh, const any_of& rh) { return rh == lh;} }; template any_of(Ts==.) => any_of; assert(state == any_of(IDLE, DISCONNECTING, DISCONNECTED)); Provide symmetric operator==

Slide 39

Slide 39 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 39/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } template friend bool operator==(const T& lh, const any_of& rh) { return rh == lh;} }; template any_of(Ts==.) => any_of; assert(state == any_of(IDLE, DISCONNECTING, DISCONNECTED)); Maybe exaggerated cuteness, but I like this!

Slide 40

Slide 40 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 40/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } template friend bool operator==(const T& lh, const any_of& rh) { return rh == lh;} }; template any_of(Ts==.) => any_of; assert(state == any_of(IDLE, DISCONNECTING, DISCONNECTED)); https://gcc.godbolt.org/z/IY865r

Slide 41

Slide 41 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 41/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } template friend bool operator==(const T& lh, const any_of& rh) { return rh == lh;} }; template any_of(Ts==.) => any_of; assert(state == any_of(IDLE, DISCONNECTING, DISCONNECTED));

Slide 42

Slide 42 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 42/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } template friend bool operator==(const T& lh, const any_of& rh) { return rh == lh;} }; template any_of(Ts==.) => any_of; assert(state == any_of(IDLE, DISCONNECTING, DISCONNECTED)); Add relational operators!

Slide 43

Slide 43 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 43/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } template bool operator<(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts < t) =| ==.);}, static_cast&>(*this)); } ==. }; while (any_of(a, b, c) < 0) ==.

Slide 44

Slide 44 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 44/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } template bool operator<(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts < t) =| ==.);}, static_cast&>(*this)); } ==. }; while (any_of(a, b, c) < 0) ==.

Slide 45

Slide 45 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 45/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } template bool operator<(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts < t) =| ==.);}, static_cast&>(*this)); } ==. }; while (any_of(a, b, c) < 0) ==. https://gcc.godbolt.org/z/YyvAtT

Slide 46

Slide 46 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 46/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } template bool operator<(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts < t) =| ==.);}, static_cast&>(*this)); } ==. }; while (any_of(a, b, c) < 0) ==.

Slide 47

Slide 47 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 47/127 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts == t) =| ==.);}, static_cast&>(*this)); } template bool operator<(const T& t) const { return std=:apply([&t](const auto&==. ts){ return ((ts < t) =| ==.);}, static_cast&>(*this)); } ==. }; while (any_of(a, b, c) < 0) ==. An awful lot of repetition here!

Slide 48

Slide 48 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 48/127 template bool or_elements(const F& f, const std=:tuple& t) { return std=:apply([&f](const auto& ==. ts){ return (f(ts) =| ==.);}, t); }

Slide 49

Slide 49 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 49/127 template bool or_elements(const F& f, const std=:tuple& t) { return std=:apply([&f](const auto& ==. ts){ return (f(ts) =| ==.);}, t); }

Slide 50

Slide 50 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 50/127 template bool or_elements(const F& f, const std=:tuple& t) { return std=:apply([&f](const auto& ==. ts){ return (f(ts) =| ==.);}, t); } template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return or_elements([&t](const auto& v){ return v == t;}, *this); } template bool operator<(const T& t) const { return or_elements([&t](const auto& v){ return v < t;}, *this); } }; while (any_of(a, b, c) < 0) ==.

Slide 51

Slide 51 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 51/127 template bool or_elements(const F& f, const std=:tuple& t) { return std=:apply([&f](const auto& ==. ts){ return (f(ts) =| ==.);}, t); } template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return or_elements([&t](const auto& v){ return v == t;}, *this); } template bool operator<(const T& t) const { return or_elements([&t](const auto& v){ return v < t;}, *this); } }; while (any_of(a, b, c) < 0) ==. https://godbolt.org/z/SP8POJ

Slide 52

Slide 52 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 52/127 template bool or_elements(const F& f, const std=:tuple& t) { return std=:apply([&f](const auto& ==. ts){ return (f(ts) =| ==.);}, t); } template struct any_of : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return or_elements([&t](const auto& v){ return v == t;}, *this); } template bool operator<(const T& t) const { return or_elements([&t](const auto& v){ return v < t;}, *this); } }; while (any_of(a, b, c) < 0) ==. each_of? Repeat Everything Again?

Slide 53

Slide 53 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 53/127 struct or_elements { template static bool apply(const F& f, const std=:tuple& t) { return std=:apply([&](const auto& ==. ts){ return (f(ts) =| ==.);}, t); } }; template struct op_t : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return Op=:apply([&t](const auto& v){ return v == t;}, *this); } ==. }; template struct any_of : op_t { using op_t=:op_t; };

Slide 54

Slide 54 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 54/127 struct or_elements { template static bool apply(const F& f, const std=:tuple& t) { return std=:apply([&](const auto& ==. ts){ return (f(ts) =| ==.);}, t); } }; template struct op_t : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return Op=:apply([&t](const auto& v){ return v == t;}, *this); } ==. }; template struct any_of : op_t { using op_t=:op_t; };

Slide 55

Slide 55 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 55/127 struct or_elements { template static bool apply(const F& f, const std=:tuple& t) { return std=:apply([&](const auto& ==. ts){ return (f(ts) =| ==.);}, t); } }; template struct op_t : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return Op=:apply([&t](const auto& v){ return v == t;}, *this); } ==. }; template struct any_of : op_t { using op_t=:op_t; };

Slide 56

Slide 56 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 56/127 struct or_elements { template static bool apply(const F& f, const std=:tuple& t) { return std=:apply([&](const auto& ==. ts){ return (f(ts) =| ==.);}, t); } }; template struct op_t : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return Op=:apply([&t](const auto& v){ return v == t;}, *this); } ==. }; template struct any_of : op_t { using op_t=:op_t; };

Slide 57

Slide 57 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 57/127 struct and_elements { template static bool apply(const F& f, const std=:tuple& t) { return std=:apply([&](const auto& ==. ts){ return (f(ts) =& ==.);}, t); } }; template struct op_t : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return Op=:apply([&t](const auto& v){ return v == t;}, *this); } ==. }; template struct each_of : op_t { using op_t=:op_t; };

Slide 58

Slide 58 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 58/127 struct and_elements { template static bool apply(const F& f, const std=:tuple& t) { return std=:apply([&](const auto& ==. ts){ return (f(ts) =& ==.);}, t); } }; template struct op_t : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return Op=:apply([&t](const auto& v){ return v == t;}, *this); } ==. }; template struct each_of : op_t { using op_t=:op_t; }; template using each_of = op_t; In a better world we could deduce constructor template args for aliases too

Slide 59

Slide 59 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 59/127 struct and_elements { template static bool apply(const F& f, const std=:tuple& t) { return std=:apply([&](const auto& ==. ts){ return (f(ts) =& ==.);}, t); } }; template struct op_t : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return Op=:apply([&t](const auto& v){ return v == t;}, *this); } ==. }; template struct each_of : op_t { using op_t=:op_t; }; template using each_of = op_t; In a better world we could deduce constructor template args for aliases too You can from C++20

Slide 60

Slide 60 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 60/127 struct and_elements { template static bool apply(const F& f, const std=:tuple& t) { return std=:apply([&](const auto& ==. ts){ return (f(ts) =& ==.);}, t); } }; template struct op_t : private std=:tuple { using std=:tuple=:tuple; template bool operator==(const T& t) const { return Op=:apply([&t](const auto& v){ return v == t;}, *this); } ==. }; template struct each_of : op_t { using op_t=:op_t; }; https://gcc.godbolt.org/z/Ay1TA_

Slide 61

Slide 61 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 61/127 Can we try something else?

Slide 62

Slide 62 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 62/127 Can we try something else? I think lambdas are cool!

Slide 63

Slide 63 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 63/127 constexpr auto tuple = [](auto ==. ts) { return [=](const auto& func) { return func(ts==.); }; }; assert(tuple(a,b,c)([](auto ==. e){ return ((e > 0) =& ==.); }));

Slide 64

Slide 64 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 64/127 constexpr auto tuple = [](auto ==. ts) { return [=](const auto& func) { return func(ts==.); }; }; assert(tuple(a,b,c)([](auto ==. e){ return ((e > 0) =& ==.); }));

Slide 65

Slide 65 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 65/127 constexpr auto tuple = [](auto ==. ts) { return [=](const auto& func) { return func(ts==.); }; }; assert(tuple(a,b,c)([](auto ==. e){ return ((e > 0) =& ==.); }));

Slide 66

Slide 66 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 66/127 constexpr auto tuple = [](auto ==. ts) { return [=](const auto& func) { return func(ts==.); }; }; constexpr auto and_elements = [](auto func) { return [=](auto ==. elements) { return (func(elements) =& ==.); }; }; assert(tuple(a,b,c)(and_elements([](auto e){ return e > 0;}));

Slide 67

Slide 67 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 67/127 constexpr auto tuple = [](auto ==. ts) { return [=](const auto& func) { return func(ts==.); }; }; constexpr auto and_elements = [](auto func) { return [=](auto ==. elements) { return (func(elements) =& ==.); }; }; assert(tuple(a,b,c)(and_elements([](auto e){ return e > 0;}));

Slide 68

Slide 68 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 68/127 constexpr auto tuple = [](auto ==. ts) { return [=](const auto& func) { return func(ts==.); }; }; constexpr auto and_elements = [](auto func) { return [=](auto ==. elements) { return (func(elements) =& ==.); }; }; assert(tuple(a,b,c)(and_elements([](auto e){ return e > 0;}));

Slide 69

Slide 69 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 69/127 constexpr auto tuple = [](auto ==. ts) { return [=](const auto& func) { return func(ts==.); }; }; constexpr auto and_elements = [](auto func) { return [=](auto ==. elements) { return (func(elements) =& ==.); }; }; constexpr auto bind_rh = [](auto func, auto rh) { return [=](auto lh) { return func(lh, rh); }; }; assert(tuple(a,b,c)(and_elements([](auto e){ return e > 0;}));

Slide 70

Slide 70 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 70/127 constexpr auto tuple = [](auto ==. ts) { return [=](const auto& func) { return func(ts==.); }; }; constexpr auto and_elements = [](auto func) { return [=](auto … elements) { return (func(elements) =& ==.); }; }; constexpr auto bind_rh = [](auto func, auto rh) { return [=](auto lh) { return func(lh, rh); }; }; constexpr auto greater_than = [](auto rh) { return bind_rh(std=:greater{}, rh); }; assert(tuple(a,b,c)(and_elements([](auto e){ return e > 0;}));

Slide 71

Slide 71 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 71/127 constexpr auto tuple = [](auto ==. ts) { return [=](const auto& func) { return func(ts==.); }; }; constexpr auto and_elements = [](auto func) { return [=](auto … elements) { return (func(elements) =& ==.); }; }; constexpr auto bind_rh = [](auto func, auto rh) { return [=](auto lh) { return func(lh, rh); }; }; constexpr auto greater_than = [](auto rh) { return bind_rh(std=:greater{}, rh); }; assert(tuple(a,b,c)(and_elements(greater_than(0)));

Slide 72

Slide 72 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 72/127 constexpr auto tuple = [](auto ==. ts) { return [=](const auto& func) { return func(ts==.); }; }; constexpr auto and_elements = [](auto func) { return [=](auto … elements) { return (func(elements) =& ==.); }; }; constexpr auto bind_rh = [](auto func, auto rh) { return [=](auto lh) { return func(lh, rh); }; }; constexpr auto greater_than = [](auto rh) { return bind_rh(std=:greater{}, rh); }; assert(tuple(a,b,c)(and_elements(greater_than(0)));

Slide 73

Slide 73 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 73/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; Func func; template auto apply(F f) const{ return tup(func(f)); } public: op_t(Func f, Tuple t) : tup(t), func(f) {} template auto operator==(const T& t) const { return apply(equal_to(t)); } template auto operator>(const T& t) const{ return apply(greater_than(t)); } }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0);

Slide 74

Slide 74 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 74/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; Func func; template auto apply(F f) const{ return tup(func(f)); } public: op_t(Func f, Tuple t) : tup(t), func(f) {} template auto operator==(const T& t) const { return apply(equal_to(t)); } template auto operator>(const T& t) const{ return apply(greater_than(t)); } }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0);

Slide 75

Slide 75 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 75/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; Func func; template auto apply(F f) const{ return tup(func(f)); } public: op_t(Func f, Tuple t) : tup(t), func(f) {} template auto operator==(const T& t) const { return apply(equal_to(t)); } template auto operator>(const T& t) const{ return apply(greater_than(t)); } }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0);

Slide 76

Slide 76 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 76/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; Func func; template auto apply(F f) const{ return tup(func(f)); } public: op_t(Func f, Tuple t) : tup(t), func(f) {} template auto operator==(const T& t) const { return apply(equal_to(t)); } template auto operator>(const T& t) const{ return apply(greater_than(t)); } }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0);

Slide 77

Slide 77 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 77/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; Func func; template auto apply(F f) const{ return tup(func(f)); } public: op_t(Func f, Tuple t) : tup(t), func(f) {} template auto operator==(const T& t) const { return apply(equal_to(t)); } template auto operator>(const T& t) const{ return apply(greater_than(t)); } }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0);

Slide 78

Slide 78 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 78/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template auto apply(F f) const{ return tup(func(f)); } public: op_t(Func f, Tuple t) : tup(t), func(f) {} template auto operator==(const T& t) const { return apply(equal_to(t)); } template auto operator>(const T& t) const{ return apply(greater_than(t)); } }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0); C++20 attribute to make empty member take no space. If saving this byte is important pre C++20, use private inheritance for Empty Base Class Optimization.

Slide 79

Slide 79 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 79/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template auto apply(F f) const{ return tup(func(f)); } public: op_t(Func f, Tuple t) : tup(t), func(f) {} template auto operator==(const T& t) const { return apply(equal_to(t)); } template auto operator>(const T& t) const{ return apply(greater_than(t)); } }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0);

Slide 80

Slide 80 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 80/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template auto apply(F f) const{ return tup(func(f)); } public: op_t(Func f, Tuple t) : tup(t), func(f) {} template auto operator==(const T& t) const { return apply(equal_to(t)); } template auto operator>(const T& t) const{ return apply(greater_than(t)); } }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0); https://gcc.godbolt.org/z/uyDzC8

Slide 81

Slide 81 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 81/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template auto apply(F f) const{ return tup(func(f)); } public: op_t(Func f, Tuple t) : tup(t), func(f) {} template auto operator==(const T& t) const { return apply(equal_to(t)); } template auto operator>(const T& t) const{ return apply(greater_than(t)); } }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0); Things to improve:

Slide 82

Slide 82 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 82/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template auto apply(F f) const{ return tup(func(f)); } public: op_t(Func f, Tuple t) : tup(t), func(f) {} template auto operator==(const T& t) const { return apply(equal_to(t)); } template auto operator>(const T& t) const{ return apply(greater_than(t)); } }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0); Things to improve: ● constexpr

Slide 83

Slide 83 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 83/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F f) const{ return tup(func(f)); } public: constexpr op_t(Func f, Tuple t) : tup(t), func(f) {} template constexpr auto operator==(const T& t) const { return apply(equal_to(t)); } template constexpr auto operator>(const T& t) const{ return apply(greater_than(t));} }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0); Things to improve: ● constexpr

Slide 84

Slide 84 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 84/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F f) const{ return tup(func(f)); } public: constexpr op_t(Func f, Tuple t) : tup(t), func(f) {} template constexpr auto operator==(const T& t) const { return apply(equal_to(t)); } template constexpr auto operator>(const T& t) const{ return apply(greater_than(t));} }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0); Things to improve: ✔ constexpr ● Perfect forwarding

Slide 85

Slide 85 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 85/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F f) const{ return tup(func(f)); } public: constexpr op_t(Func f, Tuple t) : tup(t), func(f) {} template constexpr auto operator==(const T& t) const { return apply(equal_to(t)); } template constexpr auto operator>(const T& t) const{ return apply(greater_than(t));} }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0); Things to improve: ✔ constexpr ● Perfect forwarding ● Conditional noexcept

Slide 86

Slide 86 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 86/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F f) const{ return tup(func(f)); } public: constexpr op_t(Func f, Tuple t) : tup(t), func(f) {} template constexpr auto operator==(const T& t) const { return apply(equal_to(t)); } template constexpr auto operator>(const T& t) const{ return apply(greater_than(t));} }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0); Things to improve: ✔ constexpr ● Perfect forwarding ● Conditional noexcept ● Explicit return type

Slide 87

Slide 87 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 87/127 constexpr auto tuple = [](auto ==. ts) ==. constexpr auto and_elements = [](auto func) ==. constexpr auto equal_to = [](auto rh) ==. constexpr auto greater_than = [](auto rh) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F f) const{ return tup(func(f)); } public: constexpr op_t(Func f, Tuple t) : tup(t), func(f) {} template constexpr auto operator==(const T& t) const { return apply(equal_to(t)); } template constexpr auto operator>(const T& t) const{ return apply(greater_than(t));} }; constexpr auto each_of=[](auto==.ts){ return op_t(and_elements,tuple(ts==.));}; assert(each_of(a,b,c) > 0); Things to improve: ✔ constexpr ● Perfect forwarding ● Conditional noexcept ● Explicit return type

Slide 88

Slide 88 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 88/127 constexpr auto and_elements = [](auto func) { return [=](auto ==. elements) { return (func(elements) =& ==.); }; };

Slide 89

Slide 89 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 89/127 constexpr auto and_elements = [](auto=& func) { return [func = std=:forward(func)](auto ==. elements) { return (func(elements) =& ==.); }; };

Slide 90

Slide 90 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 90/127 constexpr auto and_elements = [](auto=& func) { return [func = std=:forward(func)](auto ==. elements) { return (func(elements) =& ==.); }; };

Slide 91

Slide 91 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 91/127 constexpr auto and_elements = [](T=& func) { return [func = std=:forward(func)](auto ==. elements) { return (func(elements) =& ==.); }; }; C++20 allows us to explicitly state template parameters to lambdas.

Slide 92

Slide 92 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 92/127 constexpr auto tuple = [](auto ==. ts) { return [=](const auto& func) { return func(ts==.); }; }; constexpr auto and_elements = [](T=& func) { return [func = std=:forward(func)](auto ==. elements) { return (func(elements) =& ==.); }; };

Slide 93

Slide 93 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 93/127 constexpr auto tuple = [](auto=& ==. ts) { return [=](const auto& func) { return func(ts==.); }; }; constexpr auto and_elements = [](T=& func) { return [func = std=:forward(func)](auto ==. elements) { return (func(elements) =& ==.); }; }; Not possible to forward parameter packs in C++14 or C++17!

Slide 94

Slide 94 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 94/127 constexpr auto tuple = [](auto=& ==. ts) { return [==.ts = std=:forward(ts)](const auto& func) { return func(ts==.); }; }; constexpr auto and_elements = [](T=& func) { return [func = std=:forward(func)](auto ==. elements) { return (func(elements) =& ==.); }; }; C++20 parameter pack capture with perfect forwarding.

Slide 95

Slide 95 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 95/127 constexpr auto tuple = [](Ts=& ==. ts) { return [==.ts = std=:forward(ts)](const auto& func) { return func(ts==.); }; }; constexpr auto and_elements = [](T=& func) { return [func = std=:forward(func)](auto ==. elements) { return (func(elements) =& ==.); }; };

Slide 96

Slide 96 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 96/127 constexpr auto tuple = [](Ts=& ==. ts) ==. constexpr auto and_elements = [](T=& func) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F=& f) const { return tup(func(std=:forward(f))); } public: constexpr op_t(Func f, Tuple t) : Func(std=:move(f)), tup(std=:move(t)) {} template constexpr auto operator==(const T& t) const { return apply(equal_to(t)); } template constexpr auto operator>(const T& t) const{ return apply(greater_than(t));} }; constexpr auto each_of=[](Ts=&==. ts){ return op_t(and_elements,tuple(std=:forward(ts)==.)); };

Slide 97

Slide 97 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 97/127 constexpr auto tuple = [](Ts=& ==. ts) ==. constexpr auto and_elements = [](T=& func) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F=& f) const { return tup(func(std=:forward(f))); } public: constexpr op_t(Func f, Tuple t) : Func(std=:move(f)), tup(std=:move(t)) {} template constexpr auto operator==(const T& t) const { return apply(equal_to(t)); } template constexpr auto operator>(const T& t) const{ return apply(greater_than(t));} }; constexpr auto each_of=[](Ts=&==. ts){ return op_t(and_elements,tuple(std=:forward(ts)==.)); }; Things to improve: ✔ constexpr ✔ Perfect forwarding ● Conditional noexcept ● Explicit return type

Slide 98

Slide 98 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 98/127 constexpr auto tuple = [](Ts=& ==. ts) ==. constexpr auto and_elements = [](T=& func) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F=& f) const { return tup(func(std=:forward(f))); } public: constexpr op_t(Func f, Tuple t) : Func(std=:move(f)), tup(std=:move(t)) {} template constexpr auto operator==(const T& t) const { return apply(equal_to(t)); } template constexpr auto operator>(const T& t) const{ return apply(greater_than(t));} }; constexpr auto each_of=[](Ts=&==. ts){ return op_t(and_elements,tuple(std=:forward(ts)==.)); }; Things to improve: ✔ constexpr ✔ Perfect forwarding ● Conditional noexcept ● Explicit return type

Slide 99

Slide 99 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 99/127 constexpr auto tuple = [](Ts=& ==. ts) { return [==.ts = std=:forward(ts)](const auto& func) { return func(ts==.); }; }; constexpr auto and_elements = [](T=& func) { return [func = std=:forward(func)](auto … elements) { return (func(elements) =& ==.); }; };

Slide 100

Slide 100 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 100/127 7,82 constexpr auto tuple = [](Ts=& ==. ts) { return [==.ts = std=:forward(ts)](const auto& func) noexcept(noexcept(func(ts==.))) { return func(ts==.); }; }; constexpr auto and_elements = [](T=& func) { return [func = std=:forward(func)](auto ==. elements) noexcept(noexcept((func(elements) =& ==.))) { return (func(elements) =& ==.); }; }; Yes, double parenthesis

Slide 101

Slide 101 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 101/127 constexpr auto tuple = [](Ts=& ==. ts) { return [==.ts = std=:forward(ts)](const auto& func) noexcept(noexcept(func(ts==.))) { return func(ts==.); }; }; constexpr auto and_elements = [](T=& func) { return [func = std=:forward(func)](auto ==. elements) noexcept(noexcept((func(elements) =& ==.))) { return (func(elements) =& ==.); }; }; There’s no way around this repetition!

Slide 102

Slide 102 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 102/127 constexpr auto tuple = [](Ts=& ==. ts) ==. constexpr auto and_elements = [](T=& func) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F=& f) const noexcept(noexcept(tup(func(std=:forward(f))))) { return tup(func(std=:forward(f))); } public: constexpr op_t(Func f, Tuple t) : tup(std=:move(t)), func(std=:move(f)) {} template constexpr auto operator==(const T& t) const noexcept(noexcept(apply(equal_to(t)))) { return apply(equal_to(t)); } ==. };

Slide 103

Slide 103 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 103/127 constexpr auto tuple = [](Ts=& ==. ts) ==. constexpr auto and_elements = [](T=& func) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F=& f) const noexcept(noexcept(tup(func(std=:forward(f))))) { return tup(func(std=:forward(f))); } public: constexpr op_t(Func f, Tuple t) : tup(std=:move(t)), func(std=:move(f)) {} template constexpr auto operator==(const T& t) const noexcept(noexcept(apply(equal_to(t)))) { return apply(equal_to(t)); } ==. };

Slide 104

Slide 104 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 104/127 constexpr auto tuple = [](Ts=& ==. ts) ==. constexpr auto and_elements = [](T=& func) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F=& f) const noexcept(noexcept(tup(func(std=:forward(f))))) { return tup(func(std=:forward(f))); } public: constexpr op_t(Func f, Tuple t) : tup(std=:move(t)), func(std=:move(f)) {} template constexpr auto operator==(const T& t) const noexcept(noexcept(apply(equal_to(t)))) { return apply(equal_to(t)); } ==. }; Ugly ugly repetition!

Slide 105

Slide 105 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 105/127 constexpr auto tuple = [](Ts=& ==. ts) ==. constexpr auto and_elements = [](T=& func) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F=& f) const noexcept(noexcept(tup(func(std=:forward(f))))) { return tup(func(std=:forward(f))); } public: constexpr op_t(Func f, Tuple t) : tup(std=:move(t)), func(std=:move(f)) {} template constexpr auto operator==(const T& t) const noexcept(noexcept(apply(equal_to(t)))) { return apply(equal_to(t)); } ==. }; Things to improve: ✔ constexpr ✔ Perfect forwarding ✔ Conditional noexcept ● Explicit return type

Slide 106

Slide 106 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 106/127 constexpr auto tuple = [](Ts=& ==. ts) ==. constexpr auto and_elements = [](T=& func) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F=& f) const noexcept(noexcept(tup(func(std=:forward(f))))) { return tup(func(std=:forward(f))); } public: constexpr op_t(Func f, Tuple t) : tup(std=:move(t)), func(std=:move(f)) {} template constexpr auto operator==(const T& t) const noexcept(noexcept(apply(equal_to(t)))) { return apply(equal_to(t)); } ==. }; Things to improve: ✔ constexpr ✔ Perfect forwarding ✔ Conditional noexcept ● Explicit return type

Slide 107

Slide 107 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 107/127 constexpr auto tuple = [](Ts=& ==. ts) { return [==.ts = std=:forward(ts)](const auto& func) noexcept(noexcept(func(ts…))) { return func(ts==.); }; }; constexpr auto and_elements = [](T=& func) { return [func = std=:forward(func)](auto ==. elements) noexcept(noexcept((func(elements) =& ==.))) { return (func(elements) =& ==.); }; };

Slide 108

Slide 108 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 108/127 Yes, double parenthesis constexpr auto tuple = [](Ts=& ==. ts) { return [==.ts = std=:forward(ts)](const auto& func) noexcept(noexcept(func(ts==.))) => decltype(func(ts==.)) { return func(ts==.); }; }; constexpr auto and_elements = [](T=& func) { return [func = std=:forward(func)](auto ==. elements) noexcept(noexcept((func(elements) =& ==.))) => decltype((func(elements) =& ==.)) { return (func(elements) =& ==.); }; }; 7,82

Slide 109

Slide 109 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 109/127 constexpr auto tuple = [](Ts=& ==. ts) { return [==.ts = std=:forward(ts)](const auto& func) noexcept(noexcept(func(ts==.))) => decltype(func(ts==.)) { return func(ts==.); }; }; constexpr auto and_elements = [](T=& func) { return [func = std=:forward(func)](auto ==. elements) noexcept(noexcept((func(elements) =& ==.))) => decltype((func(elements) =& ==.)) { return (func(elements) =& ==.); }; }; "Ellie, Colorkey, cateye" by Isaril is licensed under CC BY-NC-SA 2.0 https://flic.kr/p/Jp53FM

Slide 110

Slide 110 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 110/127 constexpr auto tuple = [](Ts=& ==. ts) { return [==.ts = std=:forward(ts)](const auto& func) noexcept(noexcept(func(ts==.))) => decltype(func(ts==.)) { return func(ts==.); }; }; constexpr auto and_elements = [](T=& func) { return [func = std=:forward(func)](auto ==. elements) noexcept(noexcept((func(elements) =& ==.))) => decltype((func(elements) =& ==.)) { return (func(elements) =& ==.); }; }; www.youtube.com/watch?v=I3T4lePH-yA

Slide 111

Slide 111 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 111/127 constexpr auto tuple = [](Ts=& ==. ts) ==. constexpr auto and_elements = [](T=& func) ==. template class op_t { Tuple tup; [[no_unique_address]] Func func; template constexpr auto apply(F=& f) const noexcept(noexcept(tup(func(std=:forward(f))))) => decltype(tup(func(std=:forward(f)))) { return tup(func(std=:forward(f))); } public: constexpr op_t(Func f, Tuple t) : tup(std=:move(t)), func(std=:move(f)) {} template constexpr auto operator==(const T& t) const noexcept(noexcept(apply(equal_to(t)))) => decltype(apply(equal_to(t))) { return apply(equal_to(t)); } Things to improve: ✔ constexpr ✔ Perfect forwarding ✔ Conditional noexcept ✔ Explicit return type

Slide 112

Slide 112 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 112/127 That was

Slide 113

Slide 113 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 113/127 Modern Techniques for Keeping Your Code DRY That was

Slide 114

Slide 114 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 114/127 Björn Fahller Modern Techniques for Keeping Your Code DRY That was

Slide 115

Slide 115 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 115/127 Björn Fahller Modern Techniques for Keeping Your Code DRY That was Remember

Slide 116

Slide 116 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 116/127 Björn Fahller Modern Techniques for Keeping Your Code DRY That was Remember ● Fold expressions are awesome

Slide 117

Slide 117 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 117/127 Björn Fahller Modern Techniques for Keeping Your Code DRY Remember ● Fold expressions are awesome ● std::tuple<> and std::apply() is awsome

Slide 118

Slide 118 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 118/127 Björn Fahller Modern Techniques for Keeping Your Code DRY Remember ● Fold expressions are awesome ● std::tuple<> and std::apply() is awsome ● Higher order functions are awesome

Slide 119

Slide 119 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 119/127 Björn Fahller Modern Techniques for Keeping Your Code DRY Remember ● Fold expressions are awesome ● std::tuple<> and std::apply() is awsome ● Higher order functions are awesome ● Lambdas are awesome

Slide 120

Slide 120 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 120/127 Björn Fahller Modern Techniques for Keeping Your Code DRY Remember ● Fold expressions are awesome ● std::tuple<> and std::apply() is awsome ● Higher order functions are awesome ● Lambdas are awesome ● C++20 lambdas are awsomer!

Slide 121

Slide 121 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 121/127 Björn Fahller Modern Techniques for Keeping Your Code DRY Remember ● Fold expressions are awesome ● std::tuple<> and std::apply() is awsome ● Higher order functions are awesome ● Lambdas are awesome ● C++20 lambdas are awsomer! ● Compilers are awesome

Slide 122

Slide 122 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 122/127 Björn Fahller Modern Techniques for Keeping Your Code DRY Remember ● Fold expressions are awesome ● std::tuple<> and std::apply() is awsome ● Higher order functions are awesome ● Lambdas are awesome ● C++20 lambdas are awsomer! ● Compilers are awesome Matt Godbolt is awesome!

Slide 123

Slide 123 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 123/127 Björn Fahller Modern Techniques for Keeping Your Code DRY Remember ● Fold expressions are awesome ● std::tuple<> and std::apply() is awsome ● Higher order functions are awesome ● Lambdas are awesome ● C++20 lambdas are awsomer! ● Compilers are awesome ● noexcept/SFINAE-return is aweso^H^Hful

Slide 124

Slide 124 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 124/127 Björn Fahller Modern Techniques for Keeping Your Code DRY Remember ● Fold expressions are awesome ● std::tuple<> and std::apply() is awsome ● Higher order functions are awesome ● Lambdas are awesome ● C++20 lambdas are awsomer! ● Compilers are awesome ● noexcept/SFINAE-return is aweso^H^Hful ● Sweating the small stuff makes you annoyed

Slide 125

Slide 125 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 125/127 Björn Fahller Modern Techniques for Keeping Your Code DRY Remember ● Fold expressions are awesome ● std::tuple<> and std::apply() is awsome ● Higher order functions are awesome ● Lambdas are awesome ● C++20 lambdas are awsomer! ● Compilers are awesome ● noexcept/SFINAE-return is aweso^H^Hful ● Sweating the small stuff makes you annoyed ● But it can lead to neat code

Slide 126

Slide 126 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 126/127 Björn Fahller Modern Techniques for Keeping Your Code DRY Remember ● Fold expressions are awesome ● std::tuple<> and std::apply() is awsome ● Higher order functions are awesome ● Lambdas are awesome ● C++20 lambdas are awsomer! ● Compilers are awesome ● noexcept/SFINAE-return is aweso^H^Hful ● Sweating the small stuff makes you annoyed ● But it can lead to neat code

Slide 127

Slide 127 text

Modern DRY C++ –– code::dive 2019 © Björn Fahller @bjorn_fahller 127/127 [email protected] @bjorn_fahller @rollbear Björn Fahller Modern Techniques for Keeping Your Code DRY