本文的靈感來自於C++模板元編程技術與應用,裡面講到“
1994年,在聖迭哥舉行的一次C++標準委員會會議期間,
Erwin Unruh展示了一段特別的代碼,可以在編譯期以編譯
錯誤資訊的方式產生從2到某個給定值之間的所有質數。
”
所以自己用一下午的時間做了一個實現,代碼如下:
#include <iostream>using namespace std;/*聲明一個質數檢查器模板****i :需要被檢查的數字**factor :正在用於測試i的因數**isPrime :之前的測試是否通過,即在測試factor之前,i是否是質數*/template<int i,int factor,bool isPrime>struct PrimeChecker;template<int i,int factor>struct PrimeChecker<i,factor,true>{enum{Result=PrimeChecker<i,factor-1,i%factor!=0>::Result};};template<int i,int factor>struct PrimeChecker<i,factor,false>{enum{Result=false};};template<int i>struct PrimeChecker<i,2,true>{enum{Result=(i==2||i%2!=0)};};template<int i>struct PrimeChecker<i,1,true>{enum{Result=true};};/*一個完全特化模板.****注釋以後,編譯失敗,在之後輸出的編譯錯誤中,可以找到形如**...error: incomplete type 'Prime<X,true>' used in ...**的欄位,該欄位表示數字X為質數****解注釋以後,編譯通過,可以輸出某個範圍內的質數個數*/template<int i,bool b>struct Prime{enum{IsPrime=true};};template<int i>struct Prime<i,false>{enum{IsPrime=false};};//用於枚舉小於i的質數template<int i>struct EnumPrime{enum{PrimeCount=(Prime<i,PrimeChecker<i,i-1,true>::Result>::IsPrime?1:0)+EnumPrime<i-1>::PrimeCount};};/*一個完全特化的類模板**其實可以直接讓PrimeCount=1的**,但是為了"使用編譯期間的錯誤資訊列印質數"**,還是使用了一個等價的Prime模板*/template<>struct EnumPrime<2>{enum{PrimeCount=(Prime<2,true>::IsPrime?1:0)};};int main(){//用於編譯期間測試某個數是不是質數.如果是,運行時輸出1;否則輸出0cout<<PrimeChecker<4,3,true>::Result<<endl;//用於編譯期間計算小於某個數的質數個數cout<<EnumPrime<15>::PrimeCount<<endl;}
像這樣注釋掉Prime的定義:
/*一個完全特化模板.****注釋以後,編譯失敗,在之後輸出的編譯錯誤中,可以找到形如**...error: incomplete type 'Prime<X,true>' used in ...**的欄位,該欄位表示數字X為質數****解注釋以後,編譯通過,可以輸出某個範圍內的質數個數*/template<int i,bool b>struct Prime/*{enum{IsPrime=true};}*/;
編譯結果如下:
圖中紅框標記的輸出行,便是15以內的所有質數。
像這樣解注釋Prime的定義後,可以編譯通過,得到的運行結果如下:
/*一個完全特化模板.****注釋以後,編譯失敗,在之後輸出的編譯錯誤中,可以找到形如**...error: incomplete type 'Prime<X,true>' used in ...**的欄位,該欄位表示數字X為質數****解注釋以後,編譯通過,可以輸出某個範圍內的質數個數*/template<int i,bool b>struct Prime{enum{IsPrime=true};};
文章中提到的原始例子在這裡:
Primzahlen