用于指定任何无符号整数类型的 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>
的答案解决了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
。我还添加了一个重载来处理签名类型。
我正在尝试实现一个只接受无符号整数类型的函数。以下是我到目前为止的尝试。它适用于 "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>
事实上,考虑到问题中提供的示例,"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
。我还添加了一个重载来处理签名类型。