根据 char 的符号性专门化结构模板

Nik*_*o O 3 c++ templates c++17

template<typename T> void frobnicate()我有一个可以做事的函数。我需要 T 成为几种选择类型之一,并且我需要有关这些类型的一些信息。我通过提供特征来做到这一点:

template<typename T_Raw>
struct FrobnicationTraits
{
        static constexpr bool isValidFrobnicationType = false;
};

template<>
struct FrobnicationTraits<unsigned char>
{
        static constexpr bool isValidFrobnicationType = true;
        static constexpr bool isUnsigned = true;
        static constexpr unsigned char minValue = 0;
        static constexpr unsigned char maxValue = 255;
        //Elided in each specialization: some other values that are needed by frobnicate()
};

template<>
struct FrobnicationTraits<signed char>
{
        static constexpr bool isValidFrobnicationType = true;
        static constexpr bool isUnsigned = false;
        static constexpr signed char minValue = -128;
        static constexpr signed char maxValue =  127;
};

//Elided: versions for unsigned short and signed short
Run Code Online (Sandbox Code Playgroud)

进而:

template<typename T, typename = typename std::enable_if<FrobnicationTraits<T>::isValidFrobnicationType>::type>
void frobnicate()
{
    using Traits = FrobnicationTraits<T>;
    auto promotedMinValue = +Traits::minValue;
    auto promotedMaxValue = +Traits::maxValue;
    std::cout << "Frobnicating with " << (Traits::isUnsigned ? "unsigned" : "  signed") << " type of size " << sizeof(T) <<" between " << promotedMinValue << " and " << promotedMaxValue << std::endl;
    //...
}
Run Code Online (Sandbox Code Playgroud)

这对于这些调用来说效果很好:

int main()
{
    frobnicate<unsigned char>();  // Prints "Frobnicating with unsigned type of size 1 between 0 and 255"
    frobnicate<  signed char>();  // Prints "Frobnicating with   signed type of size 1 between -128 and 127"
    frobnicate<unsigned short>(); // Prints "Frobnicating with unsigned type of size 2 between 0 and 65535"
    frobnicate<  signed short>(); // Prints "Frobnicating with   signed type of size 2 between -32768 and 32767"
    //frobnicate<unsigned int>(); // Correctly fails to compile, because the enable_if is not satisfied, since FrobnicationTraits<unsigned int> uses the default FrobnicationTraits where isValidFrobnicationType is false
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但现在我希望能够正确frobnicate<char>()
char是实现定义为有符号或无符号的,但它始终被认为是与unsigned char和不同的类型signed char。因此,简单地调用frobnicate<char>()无法编译,因为它不会选择任何专门的 FrobnicationTraits。
我可以手动添加一项专业:

template<>
struct FrobnicationTraits<char>
{
        static constexpr bool isValidFrobnicationType = true;
        static constexpr bool isUnsigned = true;
        static constexpr char minValue = 0;
        static constexpr char maxValue = 255;
};
Run Code Online (Sandbox Code Playgroud)

但我无法提前知道这是否正确。事实上,我碰巧选择了错误的值,所以这会打印“Frobnicating with unsigned type of size 1 between 0 and -1”。

我想有效地做到这一点:

template<> // I don't know where to put the `std::enable_if<>` here, but use this if char is unsigned
struct FrobnicationTraits<char>
{
        static constexpr bool isValidFrobnicationType = true;
        static constexpr bool isUnsigned = true;
        static constexpr char minValue = 0;
        static constexpr char maxValue = 255;
};

template<> // I don't know where to put the `std::enable_if<>` here, but use this if char is signed
struct FrobnicationTraits<char>
{
        static constexpr bool isValidFrobnicationType = true;
        static constexpr bool isUnsigned = false;
        static constexpr char minValue = -128;
        static constexpr char maxValue =  127;
};
Run Code Online (Sandbox Code Playgroud)

理想情况下,解决方案不应使用预处理器。

for*_*818 6

有一个std::is_signed可以告诉你是否char签名。如果您不需要区分charsigned char/,您可以通过std::conditionalunsigned char继承其中一个来重用这些特征:

template<>
struct FrobnicationTraits<char> : FrobnicationTraits<
                                      std::conditional_t<         
                                          std::is_signed_v<char>, 
                                          signed char,
                                          unsigned char
                                      >
                                  >
{};
Run Code Online (Sandbox Code Playgroud)

也许使用一个助手:

using signed_or_unsigned_char = std::conditional_t<std::is_signed_v<char>,signed char, unsigned char>;
Run Code Online (Sandbox Code Playgroud)

然后继承FrobnicationTraits<char>FrobnicationTraits<signed_or_unsigned_char>.

PS:请注意,您的一些特征功能已经包含在std::numerical_limits. 如果直接使用std::is_signed,则特征中实际需要的只是isValidFrobnicationType.