Traits技術以一個統一的編程接口,描述各種數據類型的基本特徵。例如,對於基本類型float,如果將這種類型所能表示的最大浮點數寫爲以2爲底的指數形式,其指數部分的最大值爲128。在float.h中這個常量被定義爲FLT_MAX_EXP。而對於基本類型double,這個最大值爲1024,被定義爲DBL_MAX_EXP。類似地,float和double所能夠表示的最小正數也不一致,分別被定義爲常量FLT_EPSILON以及DBL_EPSILON。設想我們要設計一個數值分析庫,待處理的數值可以被表示爲float、double或者long double。由於這幾種類型具有不同的指數部分最大值、最小正數等特徵,如果不採用traits技術,程序的多個地方需要查詢數值的類型並依據該類型的特徵做相應的處理。使用traits技術,不同數據類型的特徵被封裝在一個類模板中,程序其他模塊可以使用這個類模板的接口,獲得每個數據類型的特徵信息。
// traits.h
#ifndef TRAITS_H
#define TRAITS_H
#define FLT_MAX_EXP (128)
#define FLT_MAX_EPSILON (0)
#define DBL_MAX_EXP (1024)
#define DBL_EPSILON (1)
// 主類模板
template <typename numT>
struct fp_traits
{
};
// 特化模板 =》float
template <>
struct fp_traits<float>
{
typedef float fp_type;
enum{ max_exponent = FLT_MAX_EXP};
static inline fp_type epsilon(){
return FLT_MAX_EPSILON;
}
};
// 特化模板=》double
template <>
struct fp_traits<double>
{
typedef double fp_type;
enum { max_exponent = DBL_MAX_EXP};
static inline fp_type epsilon(){
return DBL_EPSILON;
}
};
// 上層接口
template <typename numT>
class matrix{
public:
typedef numT num_type;
typedef fp_traits<num_type> num_type_info;
inline num_type epsilon(){
return num_type_info::epsilon();
}
};
#endif // TRAITS_H
// main.cpp
#include <QCoreApplication>
#include "traits.h"
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// traits 技術封裝 ==>給上層軟件模塊—— 類模板
// matrix提供統一的編程接口
matrix<float> fm;
matrix<double> dm;
cout << "float matrix:" << fm.epsilon() << endl;
cout << "double matrix:" << dm.epsilon() << endl;
return a.exec();
}
這兩個特化的類模板都向上層軟件提供了統一的編程接口:類型名fp_type表示其類型,枚舉常量max_exponent表示最大指數值,而靜態成員函數epsilon()返回最小正數。而上層軟件模塊——類模板matrix通過這個統一的接口獲取類型的信息。這樣,各種數據類型的差異性被封裝在類模板中,減少了上層軟件模板對這個差異性的依賴性,降低了軟件模塊之間的耦合度。相當精彩的技巧!!!