用于指定任何无符号整数类型的 C++ 模板特征

C++ template trait to specify any unsigned integral type

我正在尝试实现一个只接受无符号整数类型的函数。以下是我到目前为止的尝试。它适用于 "unsigned int",但为什么不编译 "unsigned short?"

#include <iostream>
#include <type_traits>

template<typename T, class = typename std::enable_if<std::is_unsigned<T>::value>::type>
inline const T oddProduct(T n) noexcept {
    return (n <= 1) ? n : (n % 2) ? oddProduct(n - 2)*n : oddProduct(--n);
}

int main() {
    std::cout << "Product of odd integers from 1 to 15: " << oddProduct<unsigned short>(15) << std::endl;

    return 0;
}

注意:MSVS 2017 社区 C++14 选项。

事情是由于 integral promotion:

n - 2

有一个类型 int 而不是 unsigned

您可以尝试添加 static_cast:

template<typename T, class = typename std::enable_if<std::is_unsigned<T>::value>::type>
inline const T oddProduct(T n) noexcept {
    return (n <= 1) ? n : (n % 2) ? oddProduct(static_cast<T>(n - 2))*n : oddProduct(--n);
                                               ^^^^^^^^^^^^^^
}

所以当你调用 oddProduct<unsigned short>.

n - 2 被转换为 unsigned short

另一种可能的选择是将 2 更改为 2U


另请注意,一旦您使用 C++14,您可能会使用 std::enable_if_t:

class = typename std::enable_if_t<std::is_unsigned<T>::value>

DEMO

的答案解决了OP代码中的整数提升问题,但还有另一个问题是return值类型和计算可能溢出。

事实上,考虑到问题中提供的示例,"product of odd integers from 1 to 15" 是 2027025,这个值需要超过 16 位(大小unsigned short 在大多数系统中),因此让函数 return 使用相同类型的参数会导致错误的结果。

#include <iostream>
#include <type_traits>
#include <stdexcept>

template<typename T>
inline const auto oddProduct(T n)  noexcept 
-> std::enable_if_t<std::is_unsigned<T>::value, unsigned long long> {
    return n < T{2}
        ? n
        : (n % T{2})
            ? oddProduct<T>(n - T{2})*n
            : oddProduct(--n);
}

template<typename T>
inline const auto oddProduct(T n) 
-> std::enable_if_t<std::is_signed<T>::value, unsigned long long> {
    if ( n < 0 ) throw std::domain_error("Negative value passed");
    return n < T{2}
        ? n
        : (n % T{2})
            ? oddProduct<std::make_unsigned_t<T>>(n - T{2})*n
            : oddProduct<std::make_unsigned_t<T>>(--n);
}

int main() {
    unsigned char n0 {15};
    std::cout << "Product of odd integers from 1 to 15: " << oddProduct(n0) << '\n';
    unsigned short n1 {15};
    std::cout << "Product of odd integers from 1 to 15: " << oddProduct(n1) << '\n';
    unsigned n2 {15};
    std::cout << "Product of odd integers from 1 to 15: " << oddProduct(n2) << '\n';
    short n3 {15};
    std::cout << "Product of odd integers from 1 to 15: " << oddProduct(n3) << '\n';  
}

在我的建议中,函数总是 return 是一个 unsigned long long。我还添加了一个重载来处理签名类型。