2014-10-08 14 views
5

Desidero creare una funzione che verifichi se i parametri non rientrano nell'intervallo.Confronto di tipi diversi nel modello

Ho scritto questo:

template<typename X,typename Y,typename Z > 
void checkParameter(X val, Y lower, Z upper) 
{ 
    if((val > upper) || (val < lower)) 
    { 
     log("checkParameter, val = % , lower= % , upper= % \n", val, 
          lower,upper); 
     ASSERT(false); 
    } 
} 

Tuttavia, quando faccio questo

uint32_t var = 5000; 
checkParameter(var, 0, 262143); 

ottengo l'avvertimento:

warning: comparison between signed and unsigned integer expressions 

Come posso fare una funzione che in modo sicuro sarà gestire tutti i tipi?

+6

'checkParameter (var, 0U, 262143u)' dovrebbe rimuovere l'avviso. – Jarod42

+3

Perché usi tre tipi invece di uno? Qual è il caso in cui il tipo di valore può essere diverso dai suoi limiti? – borisbn

+0

@borisbn è molto facile che ciò accada – o11c

risposta

1

Come @Borisbn detto che si potrebbe fare questo in questo modo:

template<typename type > 
void checkParameter(type val, type lower, type upper) 
{ 

    if((val > upper) || (val < lower)) 
    { 
     log("checkParameter, val = % , lower= % , upper= % \n", val, 
          lower,upper); 
     ASSERT(false); 
    } 
} 

EDIT

penso che si possa fare ciò in questo modo:

template<bool A, bool B, bool C> 
struct test { 
    template < typename T1, typename T2, typename T3> 
    void parameters (T1, T2, T3) { /* Mismatching types */ } 
}; 

template<> 
struct test<true, true, true> { // all parameters will be signed                  
    template < typename T1, typename T2, typename T3> 
    void parameters (T1 a, T2 b, T3 c) { 
    /* do your test here */ 
    } 
}; 


template<> 
struct test<false, false, false> { //all parameters will be unsigned                 
    template < typename T1, typename T2, typename T3> 
    void parameters (T1 a, T2 b, T3 c) { 
    /* do your test here */ 
    } 
}; 

template < typename T1, typename T2, typename T3> 
void testParameters(T1 a, T2 b, T3 c) { 
    test<std::is_signed<T1>::value, std::is_signed<T2>::value, std::is_signed<T3>::value>::parameters(a,b,c); 
} 
+0

Questo non riuscirà a compilare se i tipi non corrispondono, anche quando le costanti vengono passate (int di default). Non è divertente. – o11c

+0

Nota che l'OP avrà 'errore: nessuna funzione di matching per la chiamata a 'checkParameter (unsigned int &, int, int)'' nel suo caso specifico. – Jarod42

+0

Ho provato a farlo ma facendo CheckParameter (val, 0,1), dove val = uint8_t restituisce l'errore "nessuna funzione di matching per la chiamata a checkParameter (uint_8 &, int, int). Sto cambiando questa funzione ma l'altro codice esiste ancora, che non è mio. – user1876942

1

Invece di usare integrato operator <, l'uso una funzione che restituisce il risultato corretto in caso di disallineamenti di segno

template<class A, class B> 
bool lt(A a, B b) 
{ 
    if (a < 0 && b >= 0) 
     return true; 
    if (a >= 0 && b < 0) 
     return false; 
    return a < b; 
} 

Riceverai comunque avvertimenti, quindi probabilmente vorrai anche un po 'di #pragma GCC diagnostic push; ignored; pop.

+0

Invece di un pragma specifico del compilatore, è possibile risolvere questo problema con 'static_cast'ing' 0's al tipo 'A' o' B' appropriato. – Angew

+0

@Angew No, quelli non avviseranno per il segno-confronta. Loro avvertiranno del fatto che "il confronto è sempre vero", e il finale "a o11c

0

È necessario dedurre quali sono i tipi più grandi tra i tre. È possibile utilizzare questo approccio:

template<typename X, typename Y, typename Z > 
void checkParameter(X val, Y lower, Z upper) 
{ 
    using TYPE = decltype(val + lower + upper); 
    if (((TYPE) val > (TYPE) upper) || ((TYPE) val < (TYPE)lower)) 
    { 
     ASSERT(false); 
    } 
} 

il compilatore dovrebbe sostenere decltype così come questo using costrutto.

+0

Questo fallirà orribilmente quando si mischiano numeri non firmati e firmati. – o11c

+0

Si consideri 'checkParameter (std :: numeric_limits :: min(), 0u, std :: numeric_limits :: max());' –

+0

@ o11c, questo è un punto valido. Un altro asserisce che non viene passato alcun negativo. – Ajay

0

Come una combinazione di risposte di Ajay o11c di e, è possibile utilizzare questa funzione di confronto che non produce nessun avvertimento:

template<typename A, typename B> 
bool lt(A a, B b) { 
    if (a < 0 && b >= 0) 
     return true; 
    if (a >= 0 && b < 0) 
     return false; 
    using TYPE = decltype(a + b); 
    return static_cast<TYPE>(a) < static_cast<TYPE>(b); 
} 

Funziona con qualsiasi combinazione di tipi numerici firmati e non firmati.

Demo

+0

@ Jarod42 OK, corretto. –