Skip to content

Instantly share code, notes, and snippets.

@wi7a1ian
Last active November 22, 2019 11:55
Show Gist options
  • Save wi7a1ian/e71083cbec3b5233c7392261d4f3b04c to your computer and use it in GitHub Desktop.
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
enum state_type {IDLE, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED};
// the problem
assert(state == IDLE || state == DISCONNECTING || state == DISCONNECTED);
// 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));
// 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));
// 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));
// 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));
// 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));
// 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
// 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);
// 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);
// 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);
// 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