2

I am writing a function void func(K const& val), which part of a template class.

Assume I define a class object as foo<unsigned short int> f; and then I call func as f.func(999999);

What happens is the value 999999gets converted to some other value as it itself is out of range. How do I prevent this from happening? Is there a compiler flag or some other way in code where I can prevent this?

Checking

if(val > std::numeric_limits<K>::max())

inside the func does not help, as the value is already converted when it is getting passed and into something that is inside the numeric limit.

For example, 999998989898988989999 gets converted to 11823

How do I pass values greater than std::numeric_limits::max() to a function?

P.S. I am compiling using gcc (with -std=c++11)

jww
  • 97,681
  • 90
  • 411
  • 885
Chani
  • 5,055
  • 15
  • 57
  • 92

1 Answers1

2

Assuming the definition of your class foo is something like:

template<typename K>
class foo {
public:
    void func(K const& k) {}
};

You could make func template itself, and check for limits before calling the actual implementation:

#include <iostream>
#include <limits>

template<typename K>
class foo {
public:
    template<typename T>
    std::enable_if_t<std::is_signed<T>::value && !std::is_signed<K>::value> func(T const& t) 
    {
        if (t < 0 || static_cast<std::make_unsigned_t<T>>(t) > std::numeric_limits<K>::max()) {
            std::cout << "error\n";
            return;
        }
        
        func_impl(t);
    }
    
    template<typename T>
    std::enable_if_t<!std::is_signed<T>::value && std::is_signed<K>::value> func(T const& t) 
    {
        if (t > static_cast<std::make_unsigned_t<K>>(std::numeric_limits<K>::max())) {
            std::cout << "error\n";
            return;
        }
        
        func_impl(t);
    }
    
    template<typename T>
    std::enable_if_t<std::is_signed<T>::value == std::is_signed<K>::value> func(T const& k)
    {
        if (k < std::numeric_limits<K>::min() || k > std::numeric_limits<K>::max()) {
            std::cout << "error\n";
            return;
        }
        func_impl(k);
    }
    
private:
    void func_impl(K const& k) 
    {
        std::cout << "normal\n";
    }
};


int main()
{
    foo<char>().func(127);
    foo<char>().func(127u);
    foo<char>().func(-128);
    foo<char>().func(128);
    foo<char>().func(128u);
    foo<char>().func(-129);
    foo<unsigned>().func(-1);
    foo<int>().func(1u);
}

Output:

normal

normal

normal

error

error

error

error

normal

LIVE

Edit

As @BaumMitAugen pointed out, boost::numeric_cast would probably be a better alternative to manual ifs in my implementation of func - it will throw an exception if an underflow or overflow occurs and you will avoid a lot of boilerplate of the latest edited version of code which (a) works and (b) avoids signed/unsigned comparison warnings.

Community
  • 1
  • 1
Rostislav
  • 3,857
  • 18
  • 30
  • Does not work for "underflows". http://coliru.stacked-crooked.com/a/52f7f95ec70c5eb7 Let's see if I can break the overflow too. ;) But probably not, looks fine. – Baum mit Augen Nov 21 '15 at 12:10
  • @BaummitAugen Yeah, didn't test it too much. The signed/unsigned conversions should definitely be accounted for and tested extensively. The signed underflow should be fine though :) – Rostislav Nov 21 '15 at 12:15
  • Ha, got a false positive! http://coliru.stacked-crooked.com/a/25e23233d8bb3b3e This is fun. :) – Baum mit Augen Nov 21 '15 at 12:17
  • @BaummitAugen It is fun indeed. – Rostislav Nov 21 '15 at 12:29
  • Looks like that should work. Maybe throw in a `static_cast` to get rid of sign-conversion warnings. http://coliru.stacked-crooked.com/a/b9d7eaf6ca460453 Last remark: boost.numeric_cast already implements this. – Baum mit Augen Nov 21 '15 at 12:48
  • 1
    @BaummitAugen Well, that was a bit more boilerplate than I'd like to see. `boost::numeric_cast` is a way better approach (live and learn...). Plus, the latest version of code still has a lot of room to grow - limiting the code to integral types only or treating floating point ones correctly, etc. But I guess it's out of the scope for this question. Thanks for helping me improve the answer :) – Rostislav Nov 21 '15 at 13:29