問題提出:
在開發 C++ 版幾何圖形系統中, 須要求出兩個數字的最大公因子, 算法用 C 語言可寫出爲: 算法
int gcd (int x, int y) {
if (y == 0) return x;
else if (x > y) return gcd (y, x % y);
else /* x <= y */ return gcd (x, y % y);
} 數組
可是爲定義一個靜態的數組如 char buf[size], 這裏 size 是兩個編譯期已知的常量的最大公因子
的時候, 就沒法用函數來計算了, 由於函數要到運行期才能計算出結果. 而咱們須要在編譯期就知道
兩個數的最大公因子. 函數
所以, 咱們必須有什麼辦法根據已知的兩個常量, 靜態的計算出它們的最大公因子.
例如用宏的形式寫爲 #define GCD(x, y) ...某求出gcd的方法...
在 C 語言中, 是沒有辦法作到求 gcd 的靜態寫法的. 用 C++ 的模板, 才能作到. 測試
爲了實現求 gcd, 須要先作一些準備工做. 包括求兩個值的較大者, 較小者, 以及兩個數的模.
#define min(x, y) ((x) < (y) ? (x) : (y)) // 求二者中較小者.
#define max(x, y) ((x) > (y) ? (x) : (y)) // 求二者中較大者.
求二者的餘 mod 須要用模板, 由於對 0 求除會致使錯誤, 在常量表達式中不能使用. 翻譯
template <int X, int Y> struct mod {
enum { value = X % Y };
}; 遞歸
解決除 0 的問題, 用模板的偏特化版本: 開發
template <int X> struct mod <X, 0> { // X % 0
enum { value = 0 };
}; 編譯器
template <int Y> struct mod <0, Y> { // 0 % Y
enum { value = 0 };
}; 編譯
template <> struct mod<0, 0> { // 0 % 0
enum { value = 0 };
}; 模板
簡單測試 mod:
enum {
mod1 = mod<3, 4>::value, // ==> 3, 使用通常版本的 mod<>
mod2 = mod<4, 3>::value, // ==> 1, 通常版本
mod3 = mod<0, 4>::value, // ==> 0, 偏特化 x=0 的版本.
mod4 = mod<3, 0>::value, // ==> 0, 偏特化 y=0 的版本.
mod5 = mod<0, 0>::value, // ==> 0, 特化 x=0,y=0 的版本.
};
而後將 gcd 算法翻譯爲模板:
template <int X, int Y> struct gcd {
enum { amin = min (X, Y), // X, Y 中較小的一個.
amax = max (X, Y), // X, Y 中較大的一個.
amod = mod<amax, amin>::value, // X % Y 若是 X > Y
value = (Y == 0) ? X
: gcd <amin, amod>::value // 遞歸求小者 和 模 的 gcd.
};
};
再提供兩個特化的版本:
template <> struct gcd <1, 1> { enum { value = 1 }; };
template <> struct gcd <0, 0> { enum { value = 0 }; };
(也許還能提供更多的特化版本).
測試 gcd:
enum {
gcd1 = gcd<4, 3>::value, // ==> 1
gcd2 = gcd<4, 6>::value, // ==> 2
gcd3 = gcd<20, 16>::value, // ==> 4
};
如今咱們能夠定義一個靜態數組, 用以下方式了:
#define X 4 // X, Y 根據編譯器參數可能有所不一樣. 例如 X 定義爲 sizeof (int)
#define Y 6
static const int buf_size = gcd<4, 6>::value; // ==> 2
static int buf [buf_size];
最後基於 gcd 以求出最小公倍數 lcm:
#define lcm(X, Y) ((X)/gcd<(X), (Y)>::value * (Y))
enum { lcm1 = lcm(4, 6), // ==> 12 lcm2 = lcm(3, 7), // ==> 21 };