std::numeric_limits 标准库实现和应用

作用

cpp reference中介绍

std::numeric_limits是C++标准库中的一个模板类,它提供了关于基本数据类型的特性和限制的信息。

直白点说就是他提供了获取基本数据类型的相关信息的方法,让使用者不用去考虑操作系统和编译器的影响

举一个例子:

在32位程序中,int的最大值和64位程序中int的最大值是不一样的,当我们需要初始化某一个变量成int最大值的时候,需要考虑是32还是64位程序,但是如果直接使用std::numeric_limits获取int的最大值,则不用去考虑是32还是64位的程序了,这样代码也就更加简洁高效

标准库声明

namespace std {
    template<typename T>
    class numeric_limits {
    public:
        static constexpr bool is_specialized = false;
        static constexpr T min() noexcept { return T(); }
        static constexpr T max() noexcept { return T(); }
        static constexpr T lowest() noexcept { return T(); }
        static constexpr int digits = 0;
        static constexpr int digits10 = 0;
        static constexpr bool is_signed = false;
        static constexpr bool is_integer = false;
        static constexpr bool is_exact = false;
        static constexpr int radix = 0;
        static constexpr T epsilon() noexcept { return T(); }
        static constexpr T round_error() noexcept { return T(); }
        static constexpr int min_exponent = 0;
        static constexpr int min_exponent10 = 0;
        static constexpr int max_exponent = 0;
        static constexpr int max_exponent10 = 0;
        static constexpr bool has_infinity = false;
        static constexpr bool has_quiet_NaN = false;
        static constexpr bool has_signaling_NaN = false;
        static constexpr float_denorm_style has_denorm = denorm_absent;
        static constexpr bool has_denorm_loss = false;
        static constexpr T infinity() noexcept { return T(); }
        static constexpr T quiet_NaN() noexcept { return T(); }
        static constexpr T signaling_NaN() noexcept { return T(); }
        static constexpr T denorm_min() noexcept { return T(); }
        static constexpr bool is_iec559 = false;
        static constexpr bool is_bounded = false;
        static constexpr bool is_modulo = false;
        static constexpr bool traps = false;
        static constexpr bool tinyness_before = false;
        static constexpr float_round_style round_style = round_toward_zero;
    };
}

std::numeric_limits是一个模板类,使用时需要指定具体的数据类型T。该类中的所有成员函数和成员变量都是静态的,可以通过std::numeric_limits<T>::member_name的方式访问。

下面是std::numeric_limits的一些常用成员:

- is_specialized:一个布尔值,表示numeric_limits<T>是否已经为类型T进行了特化。
- min():返回类型T的最小值。
- max():返回类型T的最大值。
- lowest():返回类型T的最小有限值。
- digits:类型T的精确位数(二进制位数)。
- digits10:类型T的精确位数(十进制位数)。
- is_signed:一个布尔值,表示类型T是否是有符号类型。
- is_integer:一个布尔值,表示类型T是否是整数类型。
- is_exact:一个布尔值,表示类型T是否是精确类型。
- radix:表示类型T的基数。
- epsilon():类型T的最小可表示的绝对值。
- round_error():类型T的最小可表示的相对值。
- min_exponent:类型T的最小指数。
- min_exponent10`:类型T的最小十进制指数。
- max_exponent:类型T的最大指数。
- max_exponent10:类型T的最大十进制指数。
- has_infinity:一个布尔值,表示类型T是否有无穷大值。
- has_quiet_NaN:一个布尔值,表示类型T是否有静默NaN(Not-a-Number)值。
- has_signaling_NaN:一个布尔值,表示类型T是否有信号NaN(Not-a-Number)值。
- has_denorm:表示类型`T`的非规格化值的处理方式。
- has_denorm_loss:一个布尔值,表示类型T是否有非规格化值损失。
- infinity():返回类型T的无穷大值。
- quiet_NaN():返回类型T的静默NaN值。
- signaling_NaN():返回一个表示"signaling NaN"(信号非数)的特殊值

具体实现

std::numeric_limits 的具体实现是在编译器内实现的,这样就可以考虑到不同操作系统对标准库的影响。

例如VS2017的C++标准库中就是这么实现

namespace std {
    template<typename T>
    class numeric_limits {
    public:
        static constexpr bool is_specialized = true;
        static constexpr T min() noexcept { return _Min_value(static_cast<T*>(nullptr)); }
        static constexpr T max() noexcept { return _Max_value(static_cast<T*>(nullptr)); }
        static constexpr T lowest() noexcept { return (is_signed ? min() : T()); }
        static constexpr int digits = _Digits(static_cast<T*>(nullptr));
        static constexpr int digits10 = _Digits10(static_cast<T*>(nullptr));
        static constexpr bool is_signed = _Signed(static_cast<T*>(nullptr));
        static constexpr bool is_integer = _Integer(static_cast<T*>(nullptr));
        static constexpr bool is_exact = _Is_exact(static_cast<T*>(nullptr));
        static constexpr int radix = _Radix(static_cast<T*>(nullptr));
        static constexpr T epsilon() noexcept { return _Epsilon(static_cast<T*>(nullptr)); }
        static constexpr T round_error() noexcept { return _Round_error(static_cast<T*>(nullptr)); }
        static constexpr int min_exponent = _Min_exponent(static_cast<T*>(nullptr));
        static constexpr int min_exponent10 = _Min_exponent10(static_cast<T*>(nullptr));
        static constexpr int max_exponent = _Max_exponent(static_cast<T*>(nullptr));
        static constexpr int max_exponent10 = _Max_exponent10(static_cast<T*>(nullptr));
        static constexpr bool has_infinity = _Has_infinity(static_cast<T*>(nullptr));
        static constexpr bool has_quiet_NaN = _Has_quiet_NaN(static_cast<T*>(nullptr));
        static constexpr bool has_signaling_NaN = _Has_signaling_NaN(static_cast<T*>(nullptr));
        static constexpr float_denorm_style has_denorm = _Has_denorm(static_cast<T*>(nullptr));
        static constexpr bool has_denorm_loss = _Has_denorm_loss(static_cast<T*>(nullptr));
        static constexpr T infinity() noexcept { return _Infinity(static_cast<T*>(nullptr)); }
        static constexpr T quiet_NaN() noexcept { return _Quiet_NaN(static_cast<T*>(nullptr)); }
        static constexpr T signaling_NaN() noexcept { return _Signaling_NaN(static_cast<T*>(nullptr)); }
        static constexpr T denorm_min() noexcept { return _Denorm_min(static_cast<T*>(nullptr)); }
        static constexpr bool is_iec559 = _Is_iec559(static_cast<T*>(nullptr));
        static constexpr bool is_bounded = _Is_bounded(static_cast<T*>(nullptr));
        static constexpr bool is_modulo = _Is_modulo(static_cast<T*>(nullptr));
        static constexpr bool traps = _Traps(static_cast<T*>(nullptr));
        static constexpr bool tinyness_before = _Tinyness_before(static_cast<T*>(nullptr));
        static constexpr float_round_style round_style = _Round_style(static_cast<T*>(nullptr));
    };
}

使用案例

下面给出一个简单的使用案例

#include <iostream>
#include <limits>

int main() {
    std::cout << "Minimum value for int: " << std::numeric_limits<int>::min() << std::endl;
    std::cout << "Maximum value for int: " << std::numeric_limits<int>::max() << std::endl;
    std::cout << "Number of digits for int: " << std::numeric_limits<int>::digits << std::endl;
    std::cout << "Number of decimal digits for int: " << std::numeric_limits<int>::digits10 << std::endl;
    std::cout << "Is int signed? " << std::numeric_limits<int>::is_signed << std::endl;
    std::cout << "Is int an integer type? " << std::numeric_limits<int>::is_integer << std::endl;
    std::cout << "Is int exact? " << std::numeric_limits<int>::is_exact << std::endl;

    return 0;
}

可以看到只需要包含<limits>头文件,使用std::numeric_limits模板就可以简单获取基础类型的信息啦