numeric_limitsはデフォルトで意味無い値を提供する

C++にある numeric_limitsテンプレート は,
実装依存のarithmetic typeに関する性質を提供します.

テンプレートとは言っても, 実装依存の値を一般化して求めるなんて出来ないので,
(というかそれを提供するのが目的)
それぞれの型についての特殊化を定義してあります.


使ってみる.

#include <iostream>
#include <limits>
using std::cout;
using std::endl;
#define PRINT(expr) cout << #expr << ": " << (expr) << "\n"
int main () {
	PRINT(std::numeric_limits<int>::min());
	PRINT(std::numeric_limits<int>::max());
	PRINT(std::numeric_limits<double>::max());
	PRINT(std::numeric_limits<double>::min());
	PRINT(std::numeric_limits<int>::round_error());
	PRINT(std::numeric_limits<float>::round_error());
	PRINT(std::numeric_limits<double>::round_error());
}
/* 出力
std::numeric_limits<int>::min(): -2147483648
std::numeric_limits<int>::max(): 2147483647
std::numeric_limits<double>::max(): 1.79769e+308
std::numeric_limits<double>::min(): 2.22507e-308
std::numeric_limits<int>::round_error(): 0
std::numeric_limits<float>::round_error(): 0.5
std::numeric_limits<double>::round_error(): 0.5
*/

こんな風に型の性質が受け取れます. C++0xでは全てのメンバがconstexprになっているので
コンパイル時計算に使えますね.


で, このテンプレートは, 特殊化を提供していない型についてもデフォルトの値を返すようになっており, 例えば

template<class T> class numeric_limits {
  static constexpr T max() noexcept { return T(); }
  ...

となっています.

つまり, ライブラリがarithmetic typeを独自に定義していて, これについての特殊化が提供されていない場合, うっかりis_specialized(特殊化が提供されている型でtrueになるメンバ)を確認し忘れるとコンパイルが通ってしまい,
出鱈目な計算が進んでしまいます.

// specializeを提供しない型
struct Num {
    Num() : x_(0) {}
    Num(int x) : x_(x) {}
    int x_;
};
// 普通にmax()が受け取れる.
static_assert(numeric_limits<Num>::max()==0);

デフォルトなんて提供しない方が安全だと思うのですが….