根据编译器体系结构,使C ++函数或结构,类(使用元编程)确定有符号和无符号类型的最大值。一个用于签名,另一个用于无符号数字。
要求:
澄清:
评论之后,我对于非典型C ++问题的反应感到惊讶。我已经学会了强调,这个问题不是家庭作业,不是来自月球,而是它的实用领域。
对于所有感兴趣的应用这些东西...首先:它不是作业:)。它是practical, answerable question based on actual problems that I face - as in SO.FAQ is suggested。感谢您提供有关climits
等的提示,但我正在寻找"智能代码"。肯定是climits
,limits
经过了良好的测试和良好的代码片段,但它们非常庞大而且不一定非常聪明,技巧苛刻。我们正在寻找智能解决方案(不是"巨大的 - 任何"解决方案),我们不是吗?即使你,climits
建议也没关系,作为起点。对于那些对区域感兴趣的人,其中包括头文件是不允许的,并且源代码的大小是相关的,很少有:编译器的实验,程序转换,为编程竞赛准备问题集等。实际上它们的树与问题有关I我目前正在努力。所以我不认为(SO.FAQ)too localized,我认为,这肯定是(SO.FAQ)enthusiast programmers的问题。如果您认为即便如此,这个问题也有问题,请告诉我 - 我不想再犯错误。如果还可以,请告诉我,我可以做得更好,不要让它失败?
答案 0 :(得分:5)
在两个补语表示的合理假设下:
template<typename T> struct maxval;
template<> struct maxval<unsigned char>
{
static const unsigned char value = (unsigned char) ~0;
};
template<> struct maxval<signed char>
{
static const signed char value = ((unsigned char) ~0) >> 1;
};
template<> struct maxval<unsigned short>
{
static const unsigned short value = (unsigned short) ~0;
};
template<> struct maxval<short>
{
static const short value = ((unsigned short) ~0) >> 1;
};
int
main ()
{
std::cout << (int)maxval<signed char>::value << std::endl;
}
同样适用于其他类型。
确定最大值时需要区分有符号和无符号类型。简单的方法是枚举所有这些,如上例所示。
也许可以使用enable_if
和std::is_unsigned
的组合来完成,但重新实现它们(没有标题!)仍然需要枚举所有类型。
答案 1 :(得分:4)
对于无符号类型,它很简单:T(-1)
将始终是该类型的最大值(-1减去模数以适应范围的最大值,总是给出类型的最大值。)
对于有符号整数类型,作业几乎一样容易,至少在实践中:取最大无符号值,向右移一位,然后转换为有符号。对于将工作的C99或C ++ 11,因为只允许三个整数表示(1的补码,带符号的幅度和2的补码)(并且它给出了所有三个的正确结果)。理论上,对于C89 / 90和/或C ++ 98/03,有可能设计一个符合标准的符号类型,它将失败(例如,偏差不是范围/ 2的偏差表示)。
对于那些,以及浮点类型(没有未签名的对应物),工作更加困难。有一个原因,这些是在标题中提供的,而不是让你自己计算......
编辑:至于如何在C ++中实现这一点,大部分困难在于为无符号类型专门化模板。最明显的方法是使用SFINAE,其表达式只对签名类型合法(或仅适用于无符号类型)。通常的是一个大小类似于T()-1>0
的数组。对于有符号的类型,这将产生false,它将转换为0;由于您无法创建零大小的数组,因此尝试替换将失败。对于无符号类型,-1将“换行”到最大值,因此它将创建大小为1,这是允许的。
由于这似乎是作业,我不会为此展示一个实际的,有效的实现。
答案 2 :(得分:3)
这适用于无符号类型:
template <typename t>
constexpr t max_val() { // constexpr c++11 thing, you can remove it for c++03
return ~(t(0));
}
由于无法假设位数和编码,因此无法轻松找到signed。
答案 3 :(得分:2)
如果您希望将maxSigned与maxUnsigned合并,则可以在编译时确定签名。
#include <iostream>
#include <cstddef> // for pytdiff_t, intptr_t
template <typename T> static inline bool is_signed() {
return ~T(0) < T(1);
}
template <typename T> static inline T min_value() {
return is_signed<T>() ? ~T(0) << (sizeof(T)*8-1) : T(0);
}
template <typename T> static inline T max_value() {
return ~min_value<T>();
}
#define REPORT(type) do{ std::cout\
<< "<" #type "> is " << (is_signed<type>() ? "signed" : "unsigned")\
<< ", with lower limit " << min_value<type>()\
<< " and upper limit " << max_value<type>()\
<< std::endl; }while(false)
int main(int argc, char* argv[]) {
REPORT(char); // min, max not numeric
REPORT(int);
REPORT(unsigned);
REPORT(long long);
REPORT(unsigned long long);
REPORT(ptrdiff_t);
REPORT(size_t);
REPORT(uintptr_t);
REPORT(intptr_t);
}
答案 4 :(得分:0)
这是我的答案,因为事实上,我没有想到:枚举所有类型(如Chill),要么溢出(正如我所说 - &gt;我不想要编译器警告);正如之前的一些答案一样。这是我发现的。
如Pubby所示,无符号案例很简单:
template <class T>
T maxUnsigned(){ return ~T(0); }
在对两个补语表示的合理假设下
以下是签名案例的元编程解决方案:(元编程用于省略溢出编译器警告)
template<class T, int N> struct SignedMax {
const static T value = (T(1)<<N) + SignedMax<T, N - 1>::value;
};
template<class T> struct SignedMax<T, 0> {
const static T value = 1;
};
template<class T>
T maxSigned(){
return SignedMax<T, sizeof(T)*8-2>::value;
}
结束工作的示例
#include <iostream>
using std::cout;
using std::endl;
//(...)
#define PSIGNED(T) std::cout << #T "\t" << maxSigned<T>() << std::endl
int main(){
cout << maxSigned<short int>() << endl;
cout << maxSigned<int>() << endl;
cout << maxSigned<long long>() << endl;
cout << maxUnsigned<unsigned short int>() << endl;
cout << maxUnsigned<unsigned int>() << endl;
cout << maxUnsigned<unsigned long long>() << endl;
return 0;
}