Last active
November 22, 2019 11:55
-
-
Save wi7a1ian/e71083cbec3b5233c7392261d4f3b04c to your computer and use it in GitHub Desktop.
Modern C++ techniques based on "Modern Techniques for Keeping Your Code DRY" by Bjorn Fahller #cpp #notes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum state_type {IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED}; | |
// the problem | |
assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// using variadic function templates and fold expressions | |
template<typename ...Ts> | |
bool is_any_of(state_type s, const Ts& ... ts) | |
{ | |
return ((s == ts) || ...); | |
} | |
assert(is_any_of(state, IDLE, DISCONNECTING, DISCONNECTED)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// using variadic non-type template parameter function | |
template<state_type ...Ts> | |
bool is_any_of(state_type s) | |
{ | |
return ((s == ts) || ...); | |
} | |
assert(is_any_of<IDLE, DISCONNECTING, DISCONNECTED>(state)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// using auto for variadic non-type template parameter function | |
template<auto ...Ts, typename T> // since C++17 | |
bool is_any_of(const T& t) | |
{ | |
return ((t == ts) || ...); | |
} | |
assert(is_any_of<IDLE, DISCONNECTING, DISCONNECTED>(state)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// using functional programming: construct then test | |
template<typename T> | |
auto is_in(const T& t) | |
{ | |
return [t](const auto& ...vs){ return ((t == vs) || ...); }; | |
} | |
assert(is_in(state)(IDLE, DISCONNECTING, DISCONNECTED)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// explicit construct and compare function | |
template<typename T> | |
struct is { | |
T t; | |
template<typename ...Ts> | |
bool any_of(const Ts& ...ts) const { return ((t == ts) || ...); } | |
} | |
template<typename T> | |
is(T) -> is<T>; // C++17 deduction guide for ctor template agr deduction | |
assert(is{state}.any_of(IDLE, DISCONNECTING, DISCONNECTED)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// using tuple | |
teplate <typename ...Ts> | |
struct any_of : private std::tuple<Ts...> { | |
using std::tuple<Ts...>::tuple; // for free 18 ctors! | |
template<typename T> | |
bool operator==(const T& t) const { | |
return std::apply( | |
[&r](const auto& ...ts){ return ((ts == t) || ...); }, // call fn with each member of the tuple as param | |
static_cast<>const std::tuple<Ts...>&(*this)); | |
} | |
template <typename T> | |
friend bool operator==(const T& lh, const any_of& rh){ return rh == lh; } //symmetric operator== | |
} | |
assert(any_of(IDLE, DISCONNECTING, DISCONNECTED) == state); | |
assert(state == any_of(IDLE, DISCONNECTING, DISCONNECTED)); // symmetric |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// enabling other operators | |
teplate <typename ...Ts> | |
struct any_of : private std::tuple<Ts...> { | |
using std::tuple<Ts...>::tuple; // for free 18 ctors! | |
template<typename T> | |
bool operator==(const T& t) const { | |
return std::apply( | |
[&r](const auto& ...ts){ return ((ts == t) || ...); }, // call fn with each member of the tuple as param | |
static_cast<>const std::tuple<Ts...>&(*this)); | |
} | |
template <typename T> | |
friend bool operator==(const T& lh, const any_of& rh){ return rh == lh; } //symmetric operator== | |
template <typename T> | |
bool operator<(const T& t) const { | |
return std::apply( | |
[&r](const auto& ...ts){ return ((ts < t) || ...); }, // call fn with each member of the tuple as param | |
static_cast<>const std::tuple<Ts...>&(*this)); | |
} | |
} | |
assert(any_of(a, b, c) < 0); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// extracting || operator | |
template<typename F, typename ...Ts> | |
bool or_elements(const F& f, const std::tuple<Ts...>& t) | |
{ | |
return std::apply([&f](const auto& ...ts){ return (f(ts) || ...); }, t); | |
} | |
teplate <typename ...Ts> | |
struct any_of : private std::tuple<Ts...> { | |
using std::tuple<Ts...>::tuple; // for free 18 ctors! | |
template<typename T> | |
bool operator==(const T& t) const { | |
return or_elements([&t](const auto& v){ return v==t; }, *this); | |
} | |
template <typename T> | |
friend bool operator==(const T& lh, const any_of& rh){ return rh == lh; } //symmetric operator== | |
template<typename T> | |
bool operator<(const T& t) const { | |
return or_elements([&t](const auto& v){ return v < t; }, *this); | |
} | |
} | |
assert(any_of(a, b, c) < 0); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// adding all_of | |
struct and_elements { | |
template <typename F, typename ... Ts> | |
static bool apply(const F& f, const std::tuple<Ts...>& t) { | |
return std::apply([&](const auto& ... ts){ return (f(ts) && ...);}, t); | |
} | |
}; | |
struct or_elements { | |
template <typename F, typename ... Ts> | |
static bool apply(const F& f, const std::tuple<Ts...>& t) { | |
return std::apply([&](const auto& ... ts){ return (f(ts) || ...);}, t); | |
} | |
}; | |
template <typename Op, typename ... Ts> | |
struct op_t : private std::tuple<Ts...> { | |
using std::tuple<Ts...>::tuple; | |
template <typename T> | |
bool operator==(const T& t) const { | |
return Op::apply([&t](const auto& v){ return v == t;}, *this); | |
} | |
template <typename T> | |
bool operator<(const T& t) const { | |
return Op::apply([&t](const auto& v){ return v < t;}, *this); | |
} | |
}; | |
template <typename ... Ts> | |
struct all_of : op_t<and_elements, Ts...> { | |
using op_t<and_elements, Ts...>::op_t; | |
}; | |
template <typename ... Ts> | |
all_of(Ts...) -> all_of<Ts...>; | |
template <typename ... Ts> | |
struct any_of : op_t<or_elements, Ts...> { | |
using op_t<or_elements, Ts...>::op_t; | |
}; | |
template <typename ... Ts> | |
any_of(Ts...) -> any_of<Ts...>; | |
assert(all_of(a, b, c) < 0); | |
assert(any_of(a, b, c) < 0); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// going more functional | |
constexpr auto tuple = [](auto ...ts) // not possible to forward param packs in C++17 | |
{ | |
return [=](const auto& func) { return func(ts...); }; | |
}; | |
/* | |
// C++20 allows param pack capture with perfect forwarding | |
constexpr auto tuple = [](auto&& ...ts) | |
{ | |
return [...ts = std::forward<decltype(ts)>(ts)](const auto& func) { return func(ts...); }; | |
}; | |
// with explicitly stated template params to lambdas | |
constexpr auto tuple = []<typename ...Ts>(Ts&& ...ts) | |
{ | |
return [...ts = std::forward<Ts>(ts)](const auto& func) { return func(ts...); }; | |
}; | |
*/ | |
constexpr auto or_func = [](auto&& func) // example of no forwarding | |
{ | |
return [=](auto ... elements) { return (func(elements) || ...); }; | |
}; | |
constexpr auto and_func = [](auto&& func) // this one has perfect forwarding | |
{ | |
return [func = std::forward<decltype(func)>(func)](auto ... elements) { return (func(elements) && ...); }; | |
}; | |
constexpr auto bind_rh = []<typename Tf, typename Trh>(Tf&& func, Trh&& rh) // this one has explicitly stated template params to lambdas (C++20) | |
{ | |
return [func = std::forward<T>(func), rh = std::forward<Trh>(rh)](auto lh) { return func(lh, rh); }; | |
}; | |
constexpr auto equal_to = [](auto rh) { return bind_rh(std::equal_to{}, rh);}; | |
constexpr auto less_than = [](auto rh) { return bind_rh(std::less{}, rh);}; | |
template <typename Func, typename Tuple> | |
class op_t | |
{ | |
Tuple tup; | |
Func func; | |
template <typename F> | |
constexpr auto apply(F&& f) const { return tup(func(std::forward<F>(f))); } | |
public: | |
op_t(Func&& f, Tuple&& t) : tup(std::move(t)), func(std::move(f)) {} | |
template <typename RH> | |
constexpr auto operator==(const RH& rh) const { return apply(equal_to(rh)); } | |
template <typename LH> | |
constexpr friend auto operator==(const LH& lh, const op_t& rh) { return rh==lh; } | |
template <typename RH> | |
constexpr auto operator<(const RH& rh) const { return apply(less_than(rh)); } | |
}; | |
constexpr auto all_of = [](auto... ts) { return op_t(and_func, tuple(ts...)); }; | |
constexpr auto any_of = []<typename ...Ts>(Ts&&... ts) { return op_t(or_func, tuple(std::forward<Ts>(ts)...)); }; // C++20 | |
int ws_pos(std::string_view s) | |
{ | |
auto i = std::find_if(s.begin(), s.end(), | |
equal_to(any_of('\t', '\r', '\n', ' '))); | |
return i == s.end() ? -1 : std::distance(s.begin(), i); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment