跨平台C ++确定最大整数值(无标题)

时间:2011-11-14 21:36:59

标签: c++ architecture cross-platform metaprogramming

根据编译器体系结构,使C ++函数或结构,类(使用元编程)确定有符号和无符号类型的最大值。一个用于签名,另一个用于无符号数字。

要求:

  • 无头文件
  • 自我调整为可变大小(无stdint.h)
  • 没有关于可能的溢出的编译器警告

澄清:

评论之后,我对于非典型C ++问题的反应感到惊讶。我已经学会了强调,这个问题不是家庭作业,不是来自月球,而是它的实用领域。

对于所有感兴趣的应用这些东西...首先:它不是作业:)。它是practical, answerable question based on actual problems that I face - as in SO.FAQ is suggested。感谢您提供有关climits等的提示,但我正在寻找"智能代码"。肯定是climitslimits经过了良好的测试和良好的代码片段,但它们非常庞大而且不一定非常聪明,技巧苛刻。我们正在寻找智能解决方案(不是"巨大的 - 任何"解决方案),我们不是吗?即使你,climits建议也没关系,作为起点。对于那些对区域感兴趣的人,其中包括头文件是不允许的,并且源代码的大小是相关的,很少有:编译器的实验,程序转换,为编程竞赛准备问题集等。实际上它们的树与问题有关I我目前正在努力。所以我不认为(SO.FAQ)too localized,我认为,这肯定是(SO.FAQ)enthusiast programmers的问题。如果您认为即便如此,这个问题也有问题,请告诉我 - 我不想再犯错误。如果还可以,请告诉我,我可以做得更好,不要让它失败?

5 个答案:

答案 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_ifstd::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); }

作为Chill mentioned

  

在对两个补语表示的合理假设下

以下是签名案例的元编程解决方案:(元编程用于省略溢出编译器警告)

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