Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Construct Chainable -- A demonstration of a left-associative type constructor.
#include <utility>
#include <iostream>
// http://en.cppreference.com/w/cpp/types/decay
template< class X >
using Decay = typename std::decay<X>::type;
// ConstructBinary<T>(X,Y) = T<X,Y>
template< template<class...> class X >
struct ConstructBinary {
// Construct(const X&,const Y&) = T<X,Y>
template< class Y, class Z, class R = X< Decay<Y>, Decay<Z> > >
constexpr R operator () ( Y&& y, Z&& z ) {
return R( std::forward<Y>(y), std::forward<Z>(z) );
}
};
// Addition is an example of an associative operation.
// x + y + z = (z+y) + z
// If we let (+) be an operation that creates a pair, then
// x (+) y = (x,y)
// And if we consider this operation left associative (meaning from left to right),
// x (+) y (+) z = (z,y) (+) z = ((z,y),z)
// If we think of this as working on some type, T,
// X (+) Y (+) Z = T(X,Y) (+) Z = T( T(X,Y), Z )
template< template<class...> class X >
struct ConstructChainable : ConstructBinary<X> {
using Self = ConstructChainable<X>;
using ConstructBinary<X>::operator();
template< class Y, class Z, class A, class ...B,
class R1 = X< Decay<Y>, Decay<Z> >,
class R2 = decltype( Self()( std::declval<R1>(), std::declval<A>(),
std::declval<B>()... ) ) >
constexpr R2 operator () ( Y&& y, Z&& z, A&& a, B&& ...b ) {
return (*this) (
R1( std::forward<Y>(y), std::forward<Z>(z) ),
std::forward<A>(a), std::forward<B>(b)...
);
}
};
constexpr auto make_pair = ConstructBinary< std::pair >();
constexpr auto make_tuple = ConstructChainable< std::pair >();
template< class X, class Y >
std::ostream& operator << ( std::ostream& os, const std::pair<X,Y>& p ) {
os << '(' << p.first << ',' << p.second << ')';
return os;
}
int main() {
std::cout << make_pair(1,2) << std::endl; // p(1,2)
std::cout << make_tuple(1,2,3,4,5) << std::endl; // p( p( p( p(1,2), 3 ), 4 ) 5 )
}
@splinterofchaos

The output is (((((1,2),3),4),5)

@keveman

What's all the Decay stuff for?

@splinterofchaos

The idea is to perfect forward the arguments, but the container is supposed to contain the values. So, if passed in a int&, I want the pair to hold an int. Of coarse, you could also write a version that forwarded the type, too.

@splinterofchaos

Oh, and if you're not familiar with std::decay, it's basically like remove_reference, remove_const, and a couple other things, all rolled in to one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.