#include <type_traits>
#include <memory>
#include <iterator>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <vector>
#include <list>

template < typename ALLOCATOR, typename T >
using rebind_to_type = typename std::allocator_traits<ALLOCATOR>::template rebind_alloc<T> ;

template < typename ALLOCATOR, typename FN, typename T >
using rebind_to_result_type = rebind_to_type< ALLOCATOR, typename std::result_of< FN(T) >::type > ;

template < typename U, typename T, typename A, template<typename,typename> class CONTAINER >
CONTAINER< U, rebind_to_type<A,U> > adapt( const CONTAINER<T,A>& c )
{   return CONTAINER< U, rebind_to_type<A,U> >( c.begin(), c.end() ) ; }

template < typename T, typename A, template<typename,typename> class CONTAINER, typename FN >
CONTAINER< typename std::result_of< FN(T) >::type, rebind_to_result_type<A,FN,T> >
adapt( const CONTAINER<T,A>& c, FN fn )
{
    CONTAINER< typename std::result_of< FN(T) >::type, rebind_to_result_type<A,FN,T> > result ;
    std::transform( c.begin(), c.end(), std::back_inserter(result), fn ) ;
    return result ;
}

int main()
{
    std::cout << std::fixed << std::showpoint << std::setprecision(2) ;

    std::vector<int> vec { 64, 74, 77, 87, 58, 58, 75, 87 } ;
    for( auto i : vec ) std::cout << i << ' ' ;
    std::cout << '\n' ;

    // implicit conversion int to double => std::vector<int> => std::vector<double>
    auto vec2 = adapt<double>(vec) ;
    for( auto d : vec2 ) std::cout << d << ' ' ;
    std::cout << '\n' ;

    std::list<short> lst( vec.rbegin(), vec.rend() ) ;
    for( auto s : lst ) std::cout << s << ' ' ;
    std::cout << '\n' ;

    // explicit transformation short to double => std::list<short> => std::list<double>
    auto lst2 = adapt( lst, [] ( int v ) { return v*v / 100.0 ; } ) ;
    for( auto d : lst2 ) std::cout << d << ' ' ;
    std::cout << '\n' ;

    struct base { int i ; }; struct offset { int i ; }; struct derived : offset, base {} ;
    std::vector<derived*> vec3 { new derived, new derived, new derived } ;
    for( auto p : vec3 ) std::cout << p << ' ' ;
    std::cout << '\n' ;

    // implicit conversion derived* to base* => std::vector<base*> => std::vector<derived*>
    std::vector<base*> vec4 = adapt<base*>(vec3) ;
    for( auto p : vec4 ) std::cout << p << ' ' ;
    std::cout << '\n' ;
}
