Upgrade to Pro — share decks privately, control downloads, hide ads and more …

NDC{TechTown} - Modern Techniques for Keeping Your Code DRY

NDC{TechTown} - Modern Techniques for Keeping Your Code DRY

We have learned to avoid repeating ourselves in code, and yet we keep writing things like:

if (a > 0 && b > 0 && c > 0) ...

In this session I will show techniques from modern C++ that helps you construct abstractions for those micro repetitions. These will allow you to write:

if (all_of(a, b, c) > 0) ...

Code like this expresses intent more clearly, and therefore makes it easier to follow the logic of the intended functionality instead of focussing on code details. This makes it easier to understand the functionality, and also makes it easier to spot mistakes. Better yet, these abstractions carry no run time
cost.

After this session, you will be able to write your own zero-cost abstractions that helps getting rid of the patterns that keeps repeating in your code.

Björn Fahller

September 04, 2019
Tweet

More Decks by Björn Fahller

Other Decks in Programming

Transcript

  1. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 1/125
    Modern Techniques for Keeping Your Code DRY

    Björn Fahller

    View Slide

  2. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 2/125
    assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);

    View Slide

  3. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 3/125
    assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);

    View Slide

  4. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 4/125
    Modern Techniques for Keeping Your Code DRY

    Björn Fahller

    View Slide

  5. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 5/125
    Modern Techniques for Keeping Your Code DRY
    Björn Fahller

    View Slide

  6. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 6/125
    Modern Techniques for Keeping Your Code DRY

    Björn Fahller

    View Slide

  7. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 7/125
    enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED };
    assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);

    View Slide

  8. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 8/125
    enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED };
    assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);
    variadic function template

    View Slide

  9. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 9/125
    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);

    View Slide

  10. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 10/125
    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);

    View Slide

  11. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 11/125
    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);

    View Slide

  12. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 12/125
    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));

    View Slide

  13. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 13/125
    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!

    View Slide

  14. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 14/125
    enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED };
    assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);
    variadic non-type template parameter function template

    View Slide

  15. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 15/125
    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);

    View Slide

  16. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 16/125
    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);

    View Slide

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

    View Slide

  18. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 18/125
    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));

    View Slide

  19. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 19/125
    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

    View Slide

  20. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 20/125
    enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED };
    assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);
    construct then test

    View Slide

  21. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 21/125
    enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED };
    assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);

    View Slide

  22. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 22/125
    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);

    View Slide

  23. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 23/125
    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));

    View Slide

  24. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 24/125
    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));

    View Slide

  25. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 25/125
    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

    View Slide

  26. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 26/125
    enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED };
    assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);
    explicit construct and compare function

    View Slide

  27. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 27/125
    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);

    View Slide

  28. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 28/125
    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);

    View Slide

  29. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 29/125
    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

    View Slide

  30. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 30/125
    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

    View Slide

  31. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 31/125
    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

    View Slide

  32. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 32/125
    enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED };
    assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);
    time passes...

    View Slide

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

    View Slide

  34. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 34/125
    enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED };
    assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);
    Then one day, two years later!

    View Slide

  35. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 35/125
    enum state_type { IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED };
    assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);

    View Slide

  36. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 36/125
    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);

    View Slide

  37. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 37/125
    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);

    View Slide

  38. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 38/125
    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));

    View Slide

  39. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 39/125
    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==

    View Slide

  40. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 40/125
    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!

    View Slide

  41. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 41/125
    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

    View Slide

  42. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 42/125
    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));

    View Slide

  43. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 43/125
    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!

    View Slide

  44. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 44/125
    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) ...

    View Slide

  45. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 45/125
    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) ...

    View Slide

  46. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 46/125
    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

    View Slide

  47. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 47/125
    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) ...

    View Slide

  48. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 48/125
    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!

    View Slide

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

    View Slide

  50. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 50/125
    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) ...

    View Slide

  51. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 51/125
    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

    View Slide

  52. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 52/125
    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?

    View Slide

  53. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 53/125
    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;
    };

    View Slide

  54. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 54/125
    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;
    };

    View Slide

  55. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 55/125
    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;
    };

    View Slide

  56. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 56/125
    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;
    };

    View Slide

  57. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 57/125
    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;
    };

    View Slide

  58. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 58/125
    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

    View Slide

  59. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 59/125
    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/EAuUnM

    View Slide

  60. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 60/125
    Can we try
    something else?

    View Slide

  61. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 61/125
    Can we try
    something else?
    Lambdas are so cool!

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  65. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 65/125
    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;}));

    View Slide

  66. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 66/125
    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;}));

    View Slide

  67. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 67/125
    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;}));

    View Slide

  68. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 68/125
    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;}));

    View Slide

  69. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 69/125
    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;}));

    View Slide

  70. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 70/125
    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)));

    View Slide

  71. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 71/125
    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)));

    View Slide

  72. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 72/125
    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);

    View Slide

  73. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 73/125
    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);

    View Slide

  74. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 74/125
    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);

    View Slide

  75. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 75/125
    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);

    View Slide

  76. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 76/125
    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);

    View Slide

  77. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 77/125
    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.

    View Slide

  78. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 78/125
    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);

    View Slide

  79. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 79/125
    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

    View Slide

  80. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 80/125
    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:

    View Slide

  81. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 81/125
    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

    View Slide

  82. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 82/125
    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

    View Slide

  83. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 83/125
    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

    View Slide

  84. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 84/125
    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

    View Slide

  85. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 85/125
    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

    View Slide

  86. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 86/125
    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

    View Slide

  87. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 87/125
    constexpr auto and_elements = [](auto func)
    {
    return [=](auto ... elements) { return (func(elements) && ...); };
    };

    View Slide

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

    View Slide

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

    View Slide

  90. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 90/125
    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.

    View Slide

  91. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 91/125
    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) && ...);
    };
    };

    View Slide

  92. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 92/125
    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!

    View Slide

  93. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 93/125
    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.

    View Slide

  94. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 94/125
    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) && ...);
    };
    };

    View Slide

  95. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 95/125
    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)...));
    };

    View Slide

  96. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 96/125
    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

    View Slide

  97. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 97/125
    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

    View Slide

  98. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 98/125
    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) && ...);
    };
    };

    View Slide

  99. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 99/125
    3.08
    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

    View Slide

  100. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 100/125
    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!

    View Slide

  101. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 101/125
    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)); }
    ...
    };

    View Slide

  102. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 102/125
    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)); }
    ...
    };

    View Slide

  103. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 103/125
    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!

    View Slide

  104. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 104/125
    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

    View Slide

  105. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 105/125
    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

    View Slide

  106. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 106/125
    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) && ...);
    };
    };

    View Slide

  107. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 107/125
    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) && ...);
    };
    };
    3.08

    View Slide

  108. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 108/125
    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/

    View Slide

  109. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 109/125
    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

    View Slide

  110. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 110/125
    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

    View Slide

  111. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 111/125
    That was

    View Slide

  112. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 112/125
    Modern Techniques for Keeping Your Code DRY
    That was

    View Slide

  113. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 113/125
    Björn Fahller
    Modern Techniques for Keeping Your Code DRY
    That was

    View Slide

  114. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 114/125
    Björn Fahller
    Modern Techniques for Keeping Your Code DRY
    That was
    Remember

    View Slide

  115. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 115/125
    Björn Fahller
    Modern Techniques for Keeping Your Code DRY
    That was
    Remember

    Fold expressions are awesome

    View Slide

  116. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 116/125
    Björn Fahller
    Modern Techniques for Keeping Your Code DRY
    Remember

    Fold expressions are awesome

    std::tuple<> and std::apply() is awsome

    View Slide

  117. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 117/125
    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

    View Slide

  118. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 118/125
    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

    View Slide

  119. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 119/125
    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!

    View Slide

  120. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 120/125
    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

    View Slide

  121. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 121/125
    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

    View Slide

  122. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 122/125
    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

    View Slide

  123. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 123/125
    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

    View Slide

  124. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 124/125
    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

    View Slide

  125. Modern DRY C++ – NDC{TechTown} 2019 © Björn Fahller @bjorn_fahller 125/125
    [email protected]
    @bjorn_fahller
    @rollbear
    Björn Fahller
    Modern Techniques for Keeping Your Code DRY

    View Slide