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

时间:2018-01-22 19:31:12

标签: c++ templates traits unsigned-integer

我正在尝试实现一个只接受无符号整数类型的函数。以下是我到目前为止所尝试的内容。它适用于“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选项。

2 个答案:

答案 0 :(得分:3)

问题在于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);
                                               ^^^^^^^^^^^^^^
}

所以当您致电n - 2时,unsigned short会投放到oddProduct<unsigned short>

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

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

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

DEMO

答案 1 :(得分:0)

Edgar Rokyan的答案解决了OP代码中的整体推广问题,但是还有另一个问题,即调整返回值类型和可能的计算溢出。

事实上,考虑到问题中提供的示例,&#34;奇数整数从1到15&#34; 的乘积是2027025,这个值需要16以上位(大多数系统中unsigned short的大小),因此让函数返回相同类型的参数会导致错误的结果。

#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';  
}

在我的提案中,该函数始终返回unsigned long long。我还添加了一个重载来处理签名类型。