user1876942
user1876942

Reputation: 1501

Comparing different types in template

I want to create a function which will check if parameters are out of range.

I have written this:

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

However, when I do this

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

I get the warning:

warning: comparison between signed and unsigned integer expressions

How can I make a function which safely will handle all types?

Upvotes: 5

Views: 584

Answers (4)

Anton Savin
Anton Savin

Reputation: 41301

As a combination of o11c's and Ajay's answers, you can use this comparison function which doesn't produce any warnings:

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

It works with any combination of signed and unsigned numeric types.

Demo

Upvotes: 1

CollioTV
CollioTV

Reputation: 686

As @Borisbn said you could do this like this:

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

I think you could do this like this:

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

Upvotes: 1

o11c
o11c

Reputation: 16016

Instead of using builtin operator <, use a function that returns the correct result in case of sign mismatches

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

You'll still get warnings, so you'll probably also want some #pragma GCC diagnostic push; ignored; pop around it.

Upvotes: 1

Ajay
Ajay

Reputation: 18411

You need to deduce what is the biggest types amongst three. You may use this approach:

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

Your compiler should be supporting decltype as well as this using construct.

Upvotes: 0

Related Questions