How can I make the following differentiate between signed numbers and floating point numbers?
template<class T, typename std::enable_if<std::is_signed<T>::value>::type* = nullptr >
const char* GetTypeName(T t)
{
if (std::numeric_limits<T>::max() == std::numeric_limits<signed char>::max())
return "int8";
else if (std::numeric_limits<T>::max() == std::numeric_limits<signed short>::max())
return "int16";
else if (std::numeric_limits<T>::max() == std::numeric_limits<signed int>::max())
return "int32";
else if (std::numeric_limits<T>::max() == std::numeric_limits<signed long long>::max())
return "int64";
else
return nullptr;
}
template<class T, typename std::enable_if<std::is_unsigned<T>::value>::type* = nullptr >
const char* GetTypeName(T t)
{
if (std::numeric_limits<T>::max() == std::numeric_limits<unsigned char>::max())
return "uint8";
else if (std::numeric_limits<T>::max() == std::numeric_limits<unsigned short>::max())
return "uint16";
else if (std::numeric_limits<T>::max() == std::numeric_limits<unsigned int>::max())
return "uint32";
else if (std::numeric_limits<T>::max() == std::numeric_limits<unsigned long long>::max())
return "uint64";
else
return nullptr;
}
template<class T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr >
const char* GetTypeName(T t)
{
if (std::numeric_limits<T>::max() == std::numeric_limits<Float32>::max())
return "float";
else if (std::numeric_limits<T>::max() == std::numeric_limits<Float64>::max())
return "double";
else
return nullptr;
}
Works perfectly with integral types but it cannot differentiate between signed numbers and floating point numbers:
// Works as expected
std::string tsig = GetTypeName<signed char>(static_cast<signed char>(0));
std::string tsig = GetTypeName<signed short>(static_cast<signed short>(0));
std::string tsig = GetTypeName<signed int>(static_cast<signed int>(0));
std::string tsig = GetTypeName<signed long long>(static_cast<signed long long>(0));
// Works as expected
std::string tsig = GetTypeName<unsigned char>(static_cast<unsigned char>(0));
std::string tsig = GetTypeName<unsigned short>(static_cast<unsigned short>(0));
std::string tsig = GetTypeName<unsigned int>(static_cast<unsigned int>(0));
std::string tsig = GetTypeName<unsigned long long>(static_cast<unsigned long long>(0));
// This is ambiguous!
std::string tsig = GetTypeName<float>(static_cast<float>(0));
std::string tsig = GetTypeName<double>(static_cast<double>(0));
Use the std::is_floating_point trait along with std::is_signed.
template<class T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr >
const char* GetTypeName(T t)
{
// called for floating point types
}
template<class T, typename std::enable_if<std::is_signed<T>::value &&
!std::is_floating_point<T>::value>::type* = nullptr >
const char* GetTypeName(T t)
{
// called for signed integral types
}
Your example can be reimplemented using overload resolution too, which avoids all the if-else ifs and numeric_limits verbosity.
template<typename T>
const char *GetTypeName(T) { return "<unknown>"; }
const char *GetTypeName(signed char) { return "int8"; }
const char *GetTypeName(signed short) { return "int16"; }
const char *GetTypeName(signed int) { return "int32"; }
const char *GetTypeName(signed long) { return "int64"; }
std::cout << GetTypeName(static_cast<signed char>(0)) << std::endl;
std::cout << GetTypeName(static_cast<signed short>(0)) << std::endl;
std::cout << GetTypeName(static_cast<signed int>(0)) << std::endl;
std::cout << GetTypeName(static_cast<signed long>(0)) << std::endl;
std::cout << GetTypeName(static_cast<signed long long>(0)) << std::endl;
Live demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With