- The C++ standard library(侯捷/孟岩 译
- The C++ standard library(侯捷/孟岩 译
- The C++ standard library(侯捷/孟岩 译
- The C++ standard library(侯捷/孟岩 译
- The C++ standard library(侯捷/孟岩 译
- The C++ standard library(侯捷/孟岩 译
- The C++ standard library(侯捷/孟岩 译
- The C++ standard library(侯捷/孟岩 译
- The C++ standard library(侯捷/孟岩 译
- The C++ standard library(侯捷/孟岩 译
4. numeric limits/辅助函数/comparison operator
一般而言,数值型别(numeric types)的极值是与平台有关的。
C++标准程序库通过template numberic_limits提供这些极值,
取代传统C采用的预处理器常数(preprocessor constants)**,当然二者都可使用。
整数常数定义在<climits>和<limits.h>。
浮点数定义于<cfloat>和<float.h>
新的极值概念有两个优点:提供了更好的型别安全型;可借此写出一些template以核定(evaluate)这些极值。
note:C++ standard规定了各种型别必须保证的最小精度,如果能注意并运用这些价值就可写出与平台无关的程序。

4.1 class numeric_limits<>
使用template通常是为了对所有型别一次性的写出一个通用解决方案。但还可以在必要时以template为每个型别提供共同接口。
方法:不但提供通用性template,还提供其特化(specialization)版本,eg:numeric_limits
1. 通用性template,为所有型别提供缺省值:
namespace std
{
/* general numeric limits as default for any type
*/
template <class T>
class numeric_limits
{
public:
//no specialization for numeric limits exist
static const bool is_specialized = false;
//.. //other members that are meaningless for the general numeric limits
};
}
这个通用性template将成员is_specialized设为false,意思是对于型别T,无所谓极值的存在。
2. 各个具体型别的极值,由特化版本(specialization)提供:
namespace std
{
/* numeric limits for int
* - implementation defined
*/
template <> class numeric_limits<int>
{
public:
//yes, a specialization for numeric limits of int does exist
static const bool is_specialized = true;
static T min() throw()
{
return -2147483648;
}
static T max() throw()
{
return 2147483647;
}
static const int digits = 31;
//...
};
}
通用性numeric_limits template及其特化版本都放在<limits>头文件中。
C++ standard所囊括的特化版本涵盖了所有数值基本型别:
bool/char/signed char/unsigned char/wchar_t、
short/unsigned short/int/unsigned int/long/ float/double/long double
class numeric_limits<>所有成员及其意义如下图


4.2 float型别数值限定模板特殊化的示例(page62)
namespace std
{
template<> class numeric)limits<float>
{
public:
//yes,a specialization for numeric limits for limits of float does exist
static const bool is_specialized = true;
inline static float min() throw()
{
return 1.17549435E-38F;
}
inline static float max() throw()
{
return 3.40282347E+38F;
}
static const int digits = 24;
static const int digits10 = 6;
static const bool is_signed = true;
static const bool is_integer = false;
static const bool is_exact = false;
static const bool is_bounded = true;
static const bool is_modulo = false;
static const bool is_iec559 = true;
static const int radix = 2;
inline static float epsilon() throw()
{
return 1.19209290E-07F;
}
static const float_round_style round_style = round_to_nearest;
inline static float round_error() throw()
{
return 0.5F;
}
static const int min_exponent = -125;
static const int max_exponent = +128;
static const int min_exponent10 = -37;
static const int max_exponent10 = +38;
static const bool has_infinity = true;
inline static float infinity() throw() { return ...;}
static const bool has_quiet_NaN = true;
inline static float quiet_NaN() throw() { return ...;}
static const bool has_signaling_NaN = true;
inline static float signaling_NaN() throw() { return ...;}
static const bool has_denorm_loss = false;
inline static float infinity() throw() { return ...;}
static const bool traps = true;
static const bool tinyness_before = true;
};
}
note:数据成员是const或static,如此其值便在编译期确定;
至于函数定义的成员,某些编译器无法在编译期间确定其值。
故同一份代码在不同处理器上执行可能得出不同浮点数。

C++ standard保证,若denorm_absent为0则为false,若denorm_present为1且denorm_indeterminate为-1则二者都为true。故可把has_denorm视为一个bool以判断某型别是否允许"denormalized values"。
4.3 numeric_limits<> 使用范例(page64)
/* 此例用于展示 某些型别极值的可能运用(eg了解某型别的最大值或确定char是否有符号)
*/
#include <iostream>
#include <limits>
#include <string>
using namespace std;
int main()
{
// use textual representation for bool
cout << boolalpha;
// print maximum of integral type
cout << "max(short): " << numeric_limits<short>::max() << endl;
cout << "max(int): " << numeric_limits<int>::max() << endl;
cout << "max(long): " << numeric_limits<long>::max() << endl;
cout << endl;
// print maximum of floating-point types
cout << "max(float): " << numeric_limits<float>::max() << endl;
cout << "max(double): " << numeric_limits<double>::max() << endl;
cout << "max(long double): " << numeric_limits<long double>::max() <<endl;
// print whether char is signed
cout << "is_signed(char): " << numeric_limits<char>::is_signed << endl;
cout << endl;
// print whether numeric limits for type string exist
cout << "is_specialized(string): " <<
numeric_limits<string>::is_specialized << endl;
}
程序输出结果与执行平台有关,如下是一种可能:

4.5 辅助函数/比较操作符(page66)
4.5.1 辅助函数
算法程序库(定义于头文件<algorithm>)内含3个辅助函数,一个是两值取大,一个是两值取小,第三个用于交换两值。
1. 挑选较小值和较大值
namespace std
{
template <class T>
inline const T& min(const T& a, const T& b)
{
return b < a ? b : a;
}
template <class T>
inline const T& max(const T& a, const T& b)
{
return a < b ? b : a;
}
}
如果两值相等,通常返回第一值(程序最好不要依赖这一点)。
另一版本:接受额外的template参数作为“比较准则”
namespace std
{
template <class T , class Compare>
inline const T& min (const T& a, const T& b,Compare comp)
{
return comp(b,a) ? b : a;
}
template <class T , class Compare>
inline const T& max (const T& a, const T& b,Compare comp)
{
return comp(a,b) ? b : a;
}
}
作为“比较准则”的参数应该是函数或仿函数,接受两参数并比较:
在某指定规则下,判断第一个参数是否小于第二参数并返回判断结果。
eg,code:
#include <algorithm>
using namespace std;
/*function that compares two pointers by comparing the values to which they point
*/
bool int_ptr_less (int* a, int* b)
{
return *a < *b;
}
int main()
{
int x = 17;
int y = 42;
int* px = &x;
int* py = &y;
int* pmax;
// call max() with sepcial comparison function
pmax = max (px, py, int_ptr_lesss);
//...
}
2. 两值互换
函数swap()用于交换两对象的值。其泛型版定义于<algorithm>。
namespace std
{
template <class>
inline void swap(T& a, T& b)
{
T tmp(a);
a = b;
b = tmp;
}
}
当且仅当swap()所依赖的copy构造函数和assignment操作行为存在时,这个调用才可能有效。
swap()的最大优势:
透过template specialization或function overloading,可以为更复杂的型别提供特殊的版本:
可交换对象内部成员而不是反复赋值,如此可节约时间。
标准程序库中所有容器都用了这项技术。eg:
一个容器仅含一个array和一个成员(用于指示元素数量),那么其特化版本的swap()可以是:
class MyContainer
{
private:
int* elems; // dynamic array of elements
int* numElems; // numbers of elements
public:
//...
// implementation of swap()
void swap(MyContainer& x)
{
std::swap(elems, x.elems);
std::swap(numElems, x.numElems);
}
//...
//overloaded global swap() for this type
inline void swap(MyContainer& c1, MyContainer& c2)
{
c1.swap(c2); // calls implementation of swap()
}
};
4.5.2 辅助操作符(Comparison Operators)(page69)
有四个template functions,分别定义了!= 、>、<=、>=比较操作符,它们都是利用操作符== 和 <完成的。四个函数定义于<utility>。
namespace std
{
namespace rel_ops
{
template <class T>
inline bool operator!= (const T& x, const T& y)
{
return !(x == y);
}
template <class T>
inline bool operator> (const T& x, const T& y)
{
return y < x;
}
template <class T>
inline bool operator<= (const T& x, const T& y)
{
return !(y < x);
}
template <class T>
inline bool operator>= (const T& x, const T& y)
{
return !(x < y);
}
}
}
只要加上using namespace std::rel_pos上述四个比较操作符就自动获得了定义。
4.6 头文件<cstddef>和<cstdlib> (page71)
4.6.1 <cstddef>各种含义

NULL通常表一个不指向任何对象的指针,即0(型别是int或long),但C中NULL常定义为(void*)0。
C++ 中没定义从 void*到任何其他型别的自动转型操作。
NULL也定义于头文件<cstdio>/<cstdlib>/<cstring>/<ctime>/<cwchar>/<clocale>。
4.6.2 <cstdlib>内各种含义

常数EXIT_SUCCESS和EXIT_FAILURE用于作exit()的参数或main()的返回值。
经由atexit()注册的函数,在程序正常退出是会依注册的相反次序被一一调用,
无论是通过exit()退出或main()尾部退出,都是如此,不传递任何参数。
exit()和abort()可在任意处终止程序运行,无需返回main()。
exit()会销毁所有static对象,将所有缓冲区buffer清空,关闭所有I/O通道channels,
然后终止程序(之前会先调用由atexit()注册的函数),
若atexit()注册的函数抛出异常则会调用terminate()。
abort()会立刻终止函数且不做任何清理clean up工作。
note:这两个函数都不会销毁局部对象local objects,
因为堆栈 辗转开展动作stack inwinding 不会被执行。
为确保所有局部对象的析构函数被调用,应用异常exceptions或正常返回机制,再由main()离开。
网友评论