#include <iostream>
#include <type_traits>

template< typename T, T... VALUES  > struct seq_c { using value_type = T ; };

template< typename T, T... > struct size ;
template< typename T, T... VALUES > struct size< seq_c< T, VALUES...> >
{ static constexpr std::size_t value = sizeof...(VALUES) ; } ;

template< typename T > struct pop_front {} ;
template< typename T, T V, T... VALUES > struct pop_front< seq_c< T, V, VALUES...> >
{ using type = seq_c< T, VALUES...> ; } ;

template< std::size_t N, typename T  > struct at {} ;
template< std::size_t N, typename T, T V, T... VALUES > struct at< N, seq_c< T, V, VALUES...> >
{ static constexpr T value = at<N-1, typename pop_front< seq_c< T, V, VALUES...> >::type >::value ; } ;
template< typename T, T V, T... VALUES > struct at< 0, seq_c< T, V, VALUES...> >
{ static constexpr T value = V ; } ;
template< typename T  > struct front
{ static constexpr typename T::value_type value = at<0,T>::value ; } ;

template< typename T, T V, typename U > struct push_back {} ;
template< typename T, T V > struct push_back< T, V, seq_c<T> >
{ using type = seq_c<T,V> ; } ;
template< typename T, T V, T... VALUES > struct push_back< T, V, seq_c< T, VALUES...> >
{ using type = seq_c< T, VALUES..., V > ; } ;

template < typename T, typename U, std::size_t N = size<T>::value > struct paiwise_sum
{
    using common_type = typename std::common_type< typename T::value_type,
                                                   typename U::value_type >::type ;
    using type =  typename push_back<
                         common_type,
                         front<T>::value + front<U>::value,
                         typename paiwise_sum< typename pop_front<T>::type,
                                               typename pop_front<U>::type >::type >::type ;
};
template < typename T, typename U > struct paiwise_sum<T,U,0>
{
    using type = seq_c< typename std::common_type< typename T::value_type,
                                                   typename U::value_type >::type > ; };

template < typename T, T A, T B > struct max
{ static constexpr T value = A < B ? B : A ; } ;
template< typename T > struct max_element {};
template< typename T, T V, T... VALUES > struct max_element< seq_c< T, V, VALUES...> >
{
    using value_type = typename seq_c< T, V, VALUES...>::value_type ;
    static constexpr T value = max< T, V, max_element< seq_c< T, VALUES...> >::value >::value ;
} ;
template< typename T, T V > struct max_element< seq_c< T, V > > { static constexpr T value = V ; } ;

template < typename T > struct print {} ;
template < typename T > struct print< seq_c<T> > {};
template< typename T, T V, T... VALUES >
struct print< seq_c< T, V, VALUES...> > : print< seq_c<T,VALUES...> >
{ print() { std::cout << V << ' ' ; } } ;

int main()
{
    using a = seq_c< long long , 10, 20, 30, 40, 50 > ;
    using b = seq_c< int, -1, -17, -23, 0, -45 > ;
    using c = paiwise_sum<a,b>::type ;
    print<c>{} ;
    std::cout << "  max: " << max_element<c>::value << '\n' ;
}
 