2014-10-08 23 views
5

Chcę utworzyć funkcję, która sprawdzi, czy parametry są poza zakresem.Porównanie różnych typów w szablonie

Pisałem to:

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); 
    } 
} 

Jednak, kiedy to zrobić

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

pojawia się ostrzeżenie:

warning: comparison between signed and unsigned integer expressions 

Jak mogę utworzyć funkcję, która bezpiecznie będzie obsługuje wszystkie typy?

+6

'checkParameter (var, 0U, 262143u)' należy usunąć ostrzeżenie. – Jarod42

+3

Dlaczego używasz trzech typów zamiast jednego? Co to jest przypadek, w którym typ wartości może różnić się od jej granic? – borisbn

+0

@borisbn to bardzo łatwo, aby tak się stało – o11c

Odpowiedz

1

Jak @Borisbn powiedział, że może to zrobić tak:

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

Myślę, że można to zrobić tak:

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

Nie można skompilować, jeśli niedopasowanie typów, nawet jeśli są przekazywane stałe (domyślnie int). Nie śmieszne. – o11c

+0

Zauważ, że OP będzie miał 'error: no matching function dla wywołania 'checkParameter (unsigned int &, int, int)'' w danym przypadku. – Jarod42

+0

Próbowałem to, ale robiąc CheckParameter (val, 0,1), gdzie val = uint8_t daje błąd "brak pasującej funkcji dla wywołania checkParameter (uint_8 &, int, int). Zmieniam tę funkcję, ale drugi kod nadal istnieje, który nie jest mój. – user1876942

1

Zamiast używać wbudowanego operator <, korzystanie funkcja, która zwraca poprawny wynik w przypadku niedopasowania znaku

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; 
} 

Będziesz nadal otrzymywać ostrzeżenia, więc prawdopodobnie będziesz także potrzebować około #pragma GCC diagnostic push; ignored; pop wokół niego.

+0

Zamiast specyficznej dla kompilatora pragmy, możesz rozwiązać to przez 'static_cast'ing' 0's do odpowiedniego typu 'A' lub' B'. – Angew

+0

@Angew Nie, te nie będą ostrzegać o porównywaniu znaków. Będą ostrzegać, że "porównanie jest zawsze prawdziwe", a ostatnie "a o11c

0

Musisz wywnioskować, jakie są największe typy spośród trzech. Możesz użyć tej metody:

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); 
    } 
} 

Twój kompilator powinien wspierać decltype, jak to using konstrukt.

+0

To się nie powiedzie okropnie podczas mieszania liczb niepodpisanych i podpisanych. – o11c

+0

Rozważmy 'checkParameter (std :: numeric_limits :: min(), 0u, std :: numeric_limits :: max());' –

+0

@ o11c, to jest poprawny punkt. Niech inny twierdzi, że kontrole, do których nie ma negatywów, są przekazywane. – Ajay

0

jako kombinacja o11c i odpowiedzi Ajay, można użyć tego porównania funkcji, która nie wywołuje żadnych ostrzeżeń:

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); 
} 

Współpracuje z dowolnej kombinacji podpisanych i niepodpisanych typów liczbowych.

Demo

+0

@ Jarod42 OK, naprawione. –

Powiązane problemy