C ++ std :: enable_if区分浮点数和有符号数?

时间:2014-08-08 17:50:28

标签: c++ templates c++11 sfinae

如何区分有符号数和浮点数?

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

2 个答案:

答案 0 :(得分:7)

std::is_floating_point特征与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
}

您的示例也可以使用重载解析重新实现,这样可以避免所有if-else ifnumeric_limits详细程度。

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

答案 1 :(得分:4)

不幸的是,enable_if并不是很容易扩展。

通常,您需要调整每个重载的签名,以便它们互斥。这意味着将!std::is_floating_point<T>::value添加到有符号和无符号积分的条件中。


在您的特定情况下,但是:

#include <cstdint>

char const* GetTypeName(...) { return nullptr; }

char const* GetTypeName(int8_t) { return "int8"; }
char const* GetTypeName(int16_t) { return "int16"; }
char const* GetTypeName(int32_t) { return "int32"; }
char const* GetTypeName(int64_t) { return "int64"; }

// etc...

没有那么复杂的机器就可以工作。