Skip to content

Instantly share code, notes, and snippets.

@jzrake
Last active November 16, 2018 15:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jzrake/8ae0b0317f6c3ce2a798d597f3f4bf29 to your computer and use it in GitHub Desktop.
Save jzrake/8ae0b0317f6c3ce2a798d597f3f4bf29 to your computer and use it in GitHub Desktop.
An proof-of-concept for operator chaining in constructing algorithms
#include <functional>
// ============================================================================
namespace detail
{
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{
};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
typedef ReturnType result_type;
enum { arity = sizeof...(Args) };
template <size_t i> struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
};
};
}
template<typename Lambda>
auto make_mapping(Lambda f);
// ============================================================================
template<typename A, typename B>
struct mapping
{
mapping(std::function<B(A)> f) : f(f)
{
}
B operator()(A a) const
{
return f(a);
}
template<typename Z>
auto operator()(mapping<Z, A> other) const
{
return mapping<Z, B> ([g=f, h=other.f] (A a) { return g(h(a)); });
}
template<typename C>
auto operator|(mapping<B, C> other) const
{
return mapping<A, C> ([g=f, h=other.f] (A a) { return h(g(a)); });
}
template<typename BB>
auto operator+(mapping<A, BB> other) const
{
return mapping<A, decltype(B() + BB())> ([g=f, h=other.f] (A a) { return g(a) + h(a); });
}
template<typename BB>
auto operator-(mapping<A, BB> other) const
{
return mapping<A, decltype(B() - BB())> ([g=f, h=other.f] (A a) { return g(a) - h(a); });
}
template<typename BB>
auto operator*(mapping<A, BB> other) const
{
return mapping<A, decltype(B() * BB())> ([g=f, h=other.f] (A a) { return g(a) * h(a); });
}
template<typename BB>
auto operator/(mapping<A, BB> other) const
{
return mapping<A, decltype(B() / BB())> ([g=f, h=other.f] (A a) { return g(a) / h(a); });
}
template<typename BB>
auto operator+(BB other) const
{
return mapping<A, decltype(B() + BB())> ([g=f, h=other] (A a) { return g(a) + h; });
}
template<typename BB>
auto operator-(BB other) const
{
return mapping<A, decltype(B() - BB())> ([g=f, h=other] (A a) { return g(a) - h; });
}
template<typename BB>
auto operator*(BB other) const
{
return mapping<A, decltype(B() * BB())> ([g=f, h=other] (A a) { return g(a) * h; });
}
template<typename BB>
auto operator/(BB other) const
{
return mapping<A, decltype(B() / BB())> ([g=f, h=other] (A a) { return g(a) / h; });
}
template<typename G> auto operator()(G other) const { return operator()(make_mapping(other)); }
template<typename G> auto operator| (G other) const { return operator| (make_mapping(other)); }
std::function<B(A)> f;
};
// ============================================================================
template<typename Lambda>
auto make_mapping(Lambda f)
{
using A = typename detail::function_traits<Lambda>::template arg<0>::type;
using B = typename detail::function_traits<Lambda>::result_type;
return mapping<A, B>(f);
}
// ============================================================================
template<typename A, typename B>
auto tack(mapping<A, B> F)
{
return mapping<A, std::tuple<A, B>>([f=F.f] (A i) { return std::make_tuple(i, f(i)); });
}
// ============================================================================
#include <iostream>
int main()
{
auto f = make_mapping([] (int i) { return i; });
auto g = f | make_mapping([] (int i) { return i; });
auto h = f + make_mapping([] (int i) { return i; });
std::cout << h(1) << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment