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 999999
gets 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)
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
Edit
As @BaumMitAugen pointed out, boost::numeric_cast would probably be a better alternative to manual if
s 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.