Slide 1

Slide 1 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 1/124 Modern Techniques for Keeping Your Code DRY Björn Fahller

Slide 2

Slide 2 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 2/124 assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);

Slide 3

Slide 3 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 3/124 assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);

Slide 4

Slide 4 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 4/124 Modern Techniques for Keeping Your Code DRY Björn Fahller

Slide 5

Slide 5 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 5/124 Modern Techniques for Keeping Your Code DRY Björn Fahller

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 7/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 8/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 9/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 10/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 11/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 12/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 13/124 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED); variadic non-type template parameter function

Slide 14

Slide 14 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 14/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 15/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 16/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 17/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 18/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 19/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 20/124 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);

Slide 21

Slide 21 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 21/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 22/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 23/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 24/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 25/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 26/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 27/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 28/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 29/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 30/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 31/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 32/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 33/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 34/124 enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);

Slide 35

Slide 35 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 35/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 36/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 37/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 38/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 39/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 40/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 41/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 42/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 43/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 44/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 45/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 46/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 47/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 48/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 49/124 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 50

Slide 50 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 50/124 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 51

Slide 51 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 51/124 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) ... all_of? Repeat Everything Again?

Slide 52

Slide 52 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 52/124 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 53

Slide 53 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 53/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 54/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 55/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 56/124 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 all_of : op_t { using op_t::op_t; };

Slide 57

Slide 57 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 57/124 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 all_of : op_t { using op_t::op_t; }; template using all_of = op_t; In a better world we could deduce constructor template args for aliases too

Slide 58

Slide 58 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 58/124 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 all_of : op_t { using op_t::op_t; }; https://gcc.godbolt.org/z/Ay1TA_

Slide 59

Slide 59 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 59/124 Can we try something else?

Slide 60

Slide 60 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 60/124 Can we try something else? Lambdas are so cool!

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 63/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 64/124 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 65

Slide 65 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 65/124 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 66

Slide 66 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 66/124 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++ – StockholmCpp © Björn Fahller @bjorn_fahller 67/124 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 68

Slide 68 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 68/124 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 69

Slide 69 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 69/124 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 70

Slide 70 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 70/124 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 71

Slide 71 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 71/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0);

Slide 72

Slide 72 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 72/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0);

Slide 73

Slide 73 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 73/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0);

Slide 74

Slide 74 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 74/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0);

Slide 75

Slide 75 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 75/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0);

Slide 76

Slide 76 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 76/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_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 77

Slide 77 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 77/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0);

Slide 78

Slide 78 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 78/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0); https://gcc.godbolt.org/z/MZvLSF

Slide 79

Slide 79 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 79/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0); Things to improve:

Slide 80

Slide 80 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 80/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0); Things to improve: ● constexpr

Slide 81

Slide 81 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 81/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0); Things to improve: ● constexpr

Slide 82

Slide 82 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 82/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0); Things to improve: ✔ constexpr ● Perfect forwarding

Slide 83

Slide 83 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 83/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0); Things to improve: ✔ constexpr ● Perfect forwarding ● Conditional noexcept

Slide 84

Slide 84 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 84/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0); Things to improve: ✔ constexpr ● Perfect forwarding ● Conditional noexcept ● Explicit return type

Slide 85

Slide 85 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 85/124 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 all_of=[](auto... ts){ return op_t(and_elements,tuple(ts...));}; assert(all_of(a,b,c) > 0); Things to improve: ✔ constexpr ● Perfect forwarding ● Conditional noexcept ● Explicit return type

Slide 86

Slide 86 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 86/124 constexpr auto and_elements = [](auto func) { return [=](auto ... elements) { return (func(elements) && ...); }; };

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 89/124 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 90

Slide 90 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 90/124 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 91

Slide 91 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 91/124 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 92

Slide 92 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 92/124 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 93

Slide 93 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 93/124 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 94

Slide 94 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 94/124 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 all_of=[](Ts&&... ts){ return op_t(and_elements,tuple(std::forward(ts)...)); };

Slide 95

Slide 95 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 95/124 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 all_of=[](Ts&&... ts){ return op_t(and_elements,tuple(std::forward(ts)...)); }; Things to improve: ✔ constexpr ✔ Perfect forwarding ● Conditional noexcept ● Explicit return type

Slide 96

Slide 96 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 96/124 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 all_of=[](Ts&&... ts){ return op_t(and_elements,tuple(std::forward(ts)...)); }; Things to improve: ✔ constexpr ✔ Perfect forwarding ● Conditional noexcept ● Explicit return type

Slide 97

Slide 97 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 97/124 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 98

Slide 98 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 98/124 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 99

Slide 99 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 99/124 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(noexecpt((func(elements) && ...))) { return (func(elements) && ...); }; }; There’s no way around this repetition!

Slide 100

Slide 100 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 100/124 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 101

Slide 101 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 101/124 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 102

Slide 102 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 102/124 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 103

Slide 103 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 103/124 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 104

Slide 104 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 104/124 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 105

Slide 105 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 105/124 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 106

Slide 106 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 106/124 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 107

Slide 107 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 107/124 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) && ...); }; }; https://sacratomatovillepost.com/2017/10/03/stop-being -silly/

Slide 108

Slide 108 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 108/124 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 109

Slide 109 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 109/124 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 110

Slide 110 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 110/124 That was

Slide 111

Slide 111 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 111/124 Modern Techniques for Keeping Your Code DRY That was

Slide 112

Slide 112 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 112/124 Björn Fahller Modern Techniques for Keeping Your Code DRY That was

Slide 113

Slide 113 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 113/124 Björn Fahller Modern Techniques for Keeping Your Code DRY That was Remember

Slide 114

Slide 114 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 114/124 Björn Fahller Modern Techniques for Keeping Your Code DRY That was Remember ● Fold expressions are awesome

Slide 115

Slide 115 text

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

Slide 116

Slide 116 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 116/124 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 117

Slide 117 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 117/124 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 118

Slide 118 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 118/124 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 119

Slide 119 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 119/124 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 120

Slide 120 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 120/124 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 121

Slide 121 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 121/124 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 122

Slide 122 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 122/124 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 123

Slide 123 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 123/124 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 124

Slide 124 text

Modern DRY C++ – StockholmCpp © Björn Fahller @bjorn_fahller 124/124 [email protected] @bjorn_fahller @rollbear Björn Fahller Modern Techniques for Keeping Your Code DRY