template TypeEq(A,B) { const bool TypeEq = is(A==B); } template TypeConverts(A,B) { const bool TypeConverts = is(A:B); } template TypeConverts_r(A,B) { const bool TypeConverts_r = is(B:A); } template typelist_check_some(alias CompareOp, T, S...) { static if (S.length==0) { const typelist_check_some = false; } else static if ( CompareOp!(T,S[0]) ) { const typelist_check_some = true; } else { const typelist_check_some = typelist_check_some!(CompareOp, T, S[1..$]); } } template typelist_check_all(alias CompareOp, T, S...) { static if (S.length==0) { const typelist_check_all = true; } else static if ( CompareOp!(T,S[0]) ) { const typelist_check_all = typelist_check_all!(CompareOp, T, S[1..$]); } else { const typelist_check_all = false; } } /// Evaluates to true if is(T==S[i]) is true for some S[i] template type_equals_some_in(T, S...) { const bool type_equals_some_in = typelist_check_some!(TypeEq, T, S); } /// Evaluates to true if is(T:S[i]) is true for some S[i] template type_colon_some_in(T, S...) { const bool type_colon_some_in = typelist_check_some!(TypeConverts, T, S); } /// Evaluates to true if is(S[i]:T) is true for some S[i] template type_colon_r_some_in(T, S...) { const bool type_colon_r_some_in = typelist_check_some!(TypeConverts_r, T, S); } /// Evaluates to true if is(T==S[i]) is true for all S[i] template type_equals_all_in(T, S...) { const bool type_equals_all_in = typelist_check_all!(TypeEq, T, S); } /// Evaluates to true if is(T:S[i]) is true for all S[i] template type_colon_all_in(T, S...) { const bool type_colon_all_in = typelist_check_all!(TypeConverts, T, S); } /// Evaluates to true if is(S[i]:T) is true for all S[i] template type_colon_r_all_in(T, S...) { const bool type_colon_r_all_in = typelist_check_all!(TypeConverts_r, T, S); } template some_in(T...) { /// Check that some type in T equals some type in S template equal_some_in(S...) { static if (S.length==0) { const bool equal_some_in = false; } else static if (type_equals_some_in!(S[0],T)) { const bool equal_some_in = true; } else { const bool equal_some_in = equal_some_in!(S[1..$]); } } /// Check that some type in T can convert to some type in S, /// I.e is(T[i]:S[j]) is true for some i,j pair. template colon_some_in(S...) { static if (S.length==0) { const bool colon_some_in = false; } else static if (type_colon_r_some_in!(S[0],T)) { const bool colon_some_in = true; } else { const bool colon_some_in = colon_some_in!(S[1..$]); } } /// Check that some type in T equals all types in S template equal_all_in(S...) { static if (T.length==0) { const bool equal_all_in = false; } else static if (type_equals_all_in!(T[0],S)) { const bool equal_all_in = true; } else { const bool equal_all_in = some_in!(T[1..$]).equal_all_in!(S); } } /// Check that some type in T can convert to all types in S /// I.e for some i, is(T[i]:S[j]) is true for all j. template colon_all_in(S...) { static if (T.length==0) { const bool colon_all_in = false; } else static if (type_colon_all_in!(T[0],S)) { const bool colon_all_in = true; } else { const bool colon_all_in = some_in!(T[1..$]).colon_all_in!(S); } } } template all_in(T...) { /// Check that all types in T equal some type in S /// That is, for every T[i], there exists some S[j] such that is(T[i]==S[j]) /// though the j's may vary for each T[i]. template equal_some_in(S...) { static if (T.length==0) { const bool equal_some_in = true; } else static if (type_equals_some_in!(T[0],S)) { const bool equal_some_in = all_in!(T[1..$]).equal_some_in!(S); } else { const bool equal_some_in = false; } } /// Check that all types in T can convert to some type in S /// That is, for every T[i], there exists some S[j] such that is(T[i]:S[j]) /// though the j's may vary for each T[i]. template colon_some_in(S...) { static if (T.length==0) { const bool colon_some_in = true; } else static if (type_colon_some_in!(T[0],S)) { const bool colon_some_in = all_in!(T[1..$]).colon_some_in!(S); } else { const bool colon_some_in = false; } } /// Check that all types in T equal all types in S /// This is here for completeness, but could be useful for the case of /// a single type vs a list, in which case it is equivalent to type_equals_all_in. template equal_all_in(S...) { static if (T.length==0) { const bool equal_all_in = true; } else static if (type_equals_all_in!(T[0],S)) { const bool equal_all_in = all_in!(T[1..$]).equal_all_in!(S); } else { const bool equal_all_in = false; } } /// Check that all types in T can convert to all types in S /// I.e., for all T[i], is(T[i]:S[j]) holds for all S[j] template colon_all_in(S...) { static if (T.length==0) { const bool colon_all_in = true; } else static if (type_colon_all_in!(T[0],S)) { const bool colon_all_in = all_in!(T[1..$]).colon_all_in!(S); } else { const bool colon_all_in = false; } } } void main() { assert( type_equals_some_in!(int, float,int)); assert(!type_equals_some_in!(int, float,double)); assert( type_colon_some_in!(int, float,double)); assert(!type_colon_some_in!(cdouble, float,double)); assert( type_colon_r_some_in!(float, int,float,double)); assert(!type_colon_r_some_in!(int, float,double)); assert( type_equals_all_in!(int, int,int)); assert(!type_equals_all_in!(int, int,float)); assert( type_colon_all_in!(int, int,float,double)); assert(!type_colon_all_in!(cdouble, float,double)); assert( type_colon_r_all_in!(float, int,float,double)); assert(!type_colon_r_all_in!(int, float,double)); assert( some_in!(int,float).equal_some_in!(float,double)); assert(!some_in!(int,float).equal_some_in!(cfloat,double)); assert( some_in!(int,float).equal_all_in!(float,float)); assert(!some_in!(int,float).equal_all_in!(cfloat,double)); assert( some_in!(int,float).colon_some_in!(long,double)); assert(!some_in!(int,float).colon_some_in!(cfloat,cdouble)); assert( some_in!(int,float).colon_all_in!(float,double)); assert(!some_in!(int,float).colon_all_in!(cfloat,double)); assert( all_in!(int,float).equal_some_in!(int,float,double)); assert(!all_in!(int,float).equal_some_in!(cfloat,float,double)); assert( all_in!(int,float).colon_some_in!(long,double,cdouble)); assert(!all_in!(int,float).colon_some_in!(cfloat,cdouble)); assert( all_in!(int,int).equal_all_in!(int,int,int)); assert(!all_in!(int,float).equal_all_in!(cfloat,double)); assert( all_in!(int,float).colon_all_in!(float,double)); assert(!all_in!(int,float).colon_all_in!(cfloat,double)); }