I am implementing a generic absolute value function that handles signed and unsigned integer values correctly over the input type's domain. The std::abs(...) function leaves the case of std::abs(INT_MIN) as undefined behavior cppreference. I hope to resolve the undefined behavior by representing the returned absolute value in the input type's corresponding unsigned type. For example,
int input = INT_MIN; // -2147483648
unsigned output = integral::abs(input);
will correctly return 2147483648, but as an unsigned type.
To accomplish this I implemented the following,
namespace integral
{
template<typename integral_value_t>
auto
abs(integral_value_t const val)
{
static_assert(std::is_integral<integral_value_t>::value);
if(val < 0)
{
return static_cast<
typename std::make_unsigned<integral_value_t>::type>(-val);
}
return static_cast<
typename std::make_unsigned<integral_value_t>::type>(val);
}
}
but it created some concerns.
Concerns:
- Returning an unsigned type creates a type management challenge for the caller.
- Maybe there is a better name for the function or namespace?
- Is the
typenamekeyword required instatic_cast<typename(gcc 12.1 complained)? - Can the make_unsigned<...> call be made once? Making it twice is overly verbose.
The code is also available on godbolt.
integral_value_t new_value = val < 0 ? -val : val;, and then return themake_unsigned<...>with that new value. \$\endgroup\$using return_t = std::make_unsigned<integral_value_t>(val)::type. See godbolt for concrete example. \$\endgroup\$-valifvalis anintand its value isINT_MIN. Also see this post. \$\endgroup\$