Created
November 11, 2012 14:56
-
-
Save splinterofchaos/4055136 to your computer and use it in GitHub Desktop.
Transitivity and Associativity.
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
#include <utility> | |
using std::forward; | |
using std::declval; | |
using std::move; | |
template< class F, class X > | |
struct Part { | |
F f; | |
X x; | |
template< class _F, class _X > | |
constexpr Part( _F&& f, _X&& x ) | |
: f(forward<_F>(f)), x(forward<_X>(x)) | |
{ | |
} | |
template< class ... Xs > | |
constexpr auto operator () ( Xs&& ...xs ) | |
-> decltype( f(x,declval<Xs>()...) ) | |
{ | |
return f( x, forward<Xs>(xs)... ); | |
} | |
}; | |
template< class F, class X > struct RPart { | |
F f; | |
X x; | |
template< class _F, class _X > | |
constexpr RPart( _F&& f, _X&& x ) | |
: f( forward<_F>(f) ), x( forward<_X>(x) ) { } | |
template< class ...Y > | |
constexpr decltype( f(declval<Y>()..., x) ) | |
operator() ( Y&& ...y ) { | |
return f( forward<Y>(y)..., x ); | |
} | |
}; | |
template< class F > struct Binary { | |
template< class X > | |
constexpr Part<F,X> operator () ( X x ) { | |
return Part<F,X>( F(), move(x) ); | |
} | |
template< class X > | |
constexpr RPart<F,X> with( X x ) { | |
return RPart<F,X>( F(), move(x) ); | |
} | |
}; | |
template< class F > struct Chainable : Binary<F> { | |
using Binary<F>::operator(); | |
template< class X, class Y > | |
using R = typename std::result_of< F(X,Y) >::type; | |
// Three arguments: unroll. | |
template< class X, class Y, class Z > | |
constexpr auto operator () ( X&& x, Y&& y, Z&& z ) | |
-> R< R<X,Y>, Z > | |
{ | |
return F()( | |
F()( std::forward<X>(x), std::forward<Y>(y) ), | |
std::forward<Z>(z) | |
); | |
} | |
template< class X, class Y, class ...Z > | |
using Unroll = typename std::result_of < | |
Chainable<F>( typename std::result_of<F(X,Y)>::type, Z... ) | |
>::type; | |
// Any more? recurse. | |
template< class X, class Y, class Z, class H, class ...J > | |
constexpr auto operator () ( X&& x, Y&& y, Z&& z, H&& h, J&& ...j ) | |
-> Unroll<X,Y,Z,H,J...> | |
{ | |
// Notice how (*this) always gets applied at LEAST three arguments. | |
return (*this)( | |
F()( std::forward<X>(x), std::forward<Y>(y) ), | |
std::forward<Z>(z), std::forward<H>(h), std::forward<J>(j)... | |
); | |
} | |
}; | |
template< class F, class Fold > struct Transitive : Binary<F> { | |
using Binary<F>::operator(); | |
template< class X, class Y, class Z > | |
constexpr auto operator () ( X&& x, Y&& y, Z&& z ) | |
-> typename std::result_of<F(X,Y)>::type | |
{ | |
return Fold() ( | |
F()( forward<X>(x), forward<Y>(y) ), | |
F()( forward<Y>(y), forward<Z>(z) ) | |
); | |
} | |
template< class X, class Y, class Z, class A, class ...B > | |
constexpr auto operator () ( X&& x, Y&& y, Z&& z, A&& a, B&& ...b ) | |
-> typename std::result_of<F(X,Y)>::type | |
{ | |
return Fold() ( F()( forward<X>(x), forward<Y>(y) ), | |
F()( forward<Y>(y), forward<Z>(z), | |
forward<A>(a), forward<B>(b)... ) ); | |
} | |
}; | |
struct And : Chainable<And> { | |
using Chainable<And>::operator(); | |
template< class X, class Y > | |
constexpr auto operator () ( X&& x, Y&& y ) | |
-> decltype( declval<X>() && declval<Y>() ) | |
{ | |
return forward<X>(x) && forward<Y>(y); | |
} | |
}; | |
constexpr struct Less : Transitive<Less,And> { | |
using Transitive<Less,And>::operator(); | |
template< class X, class Y > | |
constexpr bool operator() ( X&& x, Y&& y ) { | |
return forward<X>(x) < forward<Y>(y); | |
} | |
} less{}; | |
template< template<class...> class T > struct ConstructT { | |
template< class ...X, class R = T< typename std::decay<X>::type... > > | |
constexpr R operator () ( X&& ...x ) { | |
return R( forward<X>(x)... ); | |
} | |
}; | |
template< template<class...> class T > | |
struct ConstructChainable : Chainable<ConstructT<T>> { | |
using Self = ConstructChainable<T>; | |
using Chainable<ConstructT<T>>::operator(); | |
template< class X > | |
using D = typename std::decay<X>::type; | |
template< class X, class Y, class R = T< D<X>, D<Y> > > | |
constexpr R operator () ( X&& x, Y&& y ) { | |
return R( forward<X>(x), forward<Y>(y) ); | |
} | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment