1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
#include <iostream>
#include <typeinfo>
#include <functional>
#include <tuple>
#include <type_traits>
using namespace std ;
//////////////////////////////////////////////////////////////////////////////////////////
// types S (short integer), I (integer), L(long integer), R (rational), F (real), Z (imaginary)
// defined conversions: S=>I, I=>L, L=>R, R=>F, F=>Z
struct S {}; S operator+ (S,S) { cout << "S+S\n" ; return S(); }
struct I { I() {} I(S) { cout << "S => I : " ; } }; I operator+ (I,I) { cout << "I+I\n" ; return I(); }
struct L { L() {} L(I) { cout << "I => L : " ; } }; L operator+ (L,L) { cout << "L+L\n" ; return L(); }
struct R { R() {} R(L) { cout << "L => R : " ; } }; R operator+ (R,R) { cout << "R+R\n" ; return R(); }
struct F { F() {} F(R) { cout << "R => F : " ; } }; F operator+ (F,F) { cout << "F+F\n" ; return F(); }
struct Z { Z() {} Z(R) { cout << "R => Z : " ; } }; Z operator+ (Z,Z) { cout << "Z+Z\n" ; return Z(); }
//////////////////////////////////////////////////////////////////////////////////////////
// typelist with functionality to retrieve the next type in the list
template< typename... TYPES > struct typelist {};
template< unsigned int N, typename... TYPES > struct at {} ;
template< unsigned int N, typename... TYPES > struct at< N, typelist<TYPES...> >
{ typedef typename tuple_element< N, tuple<TYPES...> >::type type ; };
template< typename T, typename U, int N = 0 > struct indexof ;
template< typename T, int N > struct indexof< T, typelist<>, N > { enum { value = -1 } ; };
template< typename T, typename FIRST, typename ...REST, int N >
struct indexof< T, typelist<FIRST,REST...>, N >
: conditional< is_same<T,FIRST>::value,
integral_constant<int,N>,
indexof< T, typelist<REST...>, N+1 > >::type {} ;
template < typename T, typename TLIST > struct next_wider_type
{ typedef typename at< indexof<T,TLIST>::value+1, TLIST >::type type ; } ;
// our typelist is ordered as S,I,L,R,F,Z in the order of conversions narrower type => wider type
typedef typelist<S,I,L,R,F,Z> TYPELIST ;
////////////////////////////////////////////////////////////////////////////////////////////
// cascaded upcast from SRCE => DEST - if there is a direct convesion from SRCE=>DEST, use it
template < typename SRCE, typename DEST, typename TLIST = TYPELIST >
DEST lift( SRCE s,
typename enable_if< is_convertible<SRCE,DEST>::value, void >::type* = nullptr )
{ return DEST(s) ; }
// if not, cast SRCE up by one level to the next wider type and try again
template < typename SRCE, typename DEST, typename TLIST = TYPELIST >
DEST lift( SRCE s,
typename enable_if< !is_convertible<SRCE,DEST>::value, void >::type* = nullptr )
{
typedef typename next_wider_type<SRCE,TLIST>::type wider_type ;
return lift< wider_type, DEST, TLIST >( wider_type(s) ) ;
}
// helper to determine the wider type
template< typename A, typename B > struct wider_type
{
typedef typename conditional< ( indexof<A,TYPELIST>::value > indexof<B,TYPELIST>::value ),
A, B >::type type ;
};
//////////////////////////////////////////////////////////////////////////////////////////////
template< typename A, typename B > inline
typename wider_type<A,B>::type operator + ( A a, B b )
{
typedef typename wider_type<A,B>::type type ;
return lift<A,type>(a) + lift<B,type>(b);
}
///////////////////////////////////////////////////////////////////////////////////////////////
int main() // perfunctory test driver
{
cout << "S+Z : " ; Z z1 = S() + Z() ;
cout << "Z+S : " ; Z z2 = Z() + S() ;
cout << "I+R : " ; R r1 = I() + R() ;
cout << "R+F : " ; F f1 = R() + F() ;
}
|