上一篇使用了enum來類比編譯時間常數,但是c++編譯時間的常數也是有類型的(c僅僅只有int和double。什嗎?你居然不知道c語言中sizeof('1')==sizeof(1)?)。所以很多編譯器吐出海量的警告是很正常的。不過誰讓哥心軟,要相容vc6呢?唉,於是又準備了若干宏,給大家選擇編譯,另外把代碼的版式也規整了一下。如果想在一些比較不標準的編譯器上通過編譯,那麼就要做好接受警告的心理準備。如果你是一位boost綜合症的重症患者,是否會覺得下面的菜很合自己的胃口呢?
(選擇宏STATIC_CONST:選擇enum或者static const作為編譯期常數定義的方法。前者本質只支援int並且英特爾編譯器在做負數轉換的時候常常會掛,用作bool判斷時編譯器會警告,警告的形式各有不同,但是幾乎所有的編譯器都支援,不報錯,相容性最佳。後者很精確,但是vc6不支援.....)
上菜咯。
<br />#include <iostream><br />using namespace std;<br />//#define STATIC_CONST(type, name, value) static const type name = type(value) //Try the one below if your compiler doesn't support static const.<br />#define STATIC_CONST(type, name, value) enum {name = type(value)} //Some compiler will crash so be careful! Warning comes if size_t is not used!<br />STATIC_CONST(size_t, stop_tag, -1);<br />/* Binary search between [M1,M2]*/<br />template< size_t N, size_t M1 , size_t M2 >//Assert M1<=M2<=N<br />struct sqrt_check<br />{<br />protected:<br />STATIC_CONST(size_t, middle, (M1 + M2)/2);<br />STATIC_CONST(bool, end, (M1 * M1 == N || M2 * M2 == N || M1 == middle || middle * middle == N));<br />STATIC_CONST(bool, selector, middle * middle > N);</p><p>public:<br />STATIC_CONST(size_t, result,(<br /> N== M1 * M1 ?<br />M1 : N == M2 * M2 ?<br />M2 : M1 == middle ?//|M1-M2|=1, which means M1*M1 <= N < =M2*M2<br />M1 : N == middle * middle ?//Bsearch begin!<br />middle : selector ?<br /> sqrt_check<end ? stop_tag : N, end ? stop_tag : M1, end ? stop_tag : middle>::result<br />: sqrt_check<end ? stop_tag : N, end ? stop_tag : middle, end ? stop_tag : M2>::result)<br />);<br />};<br />template<><br />struct sqrt_check< stop_tag, stop_tag, stop_tag ><br />{<br />STATIC_CONST(size_t, result, stop_tag);//Stop here!<br />};<br />template < size_t N, size_t M1, size_t M2 ><br />struct sqrt_check_newton<br />{<br />protected:<br />STATIC_CONST(size_t, next, (M1 + N/M1)/2);//newton iterator method<br />STATIC_CONST(bool, end, (next == M1 || next == M2 || next * next== N));<br />public:<br />STATIC_CONST(size_t, result,(<br /> (N == next * next || M1 == next) ?//Fixed Point不動點<br />next : M2 == next ?//|M1-M2|=1, which means M1*M1 <= N < =M2*M2 來回擺動<br />(M2 + M1)/2: sqrt_check_newton<(end ? stop_tag : N), (end ? stop_tag : next), (end ? stop_tag : M1)>::result)<br />);<br />};<br />template<><br />struct sqrt_check_newton< stop_tag, stop_tag, stop_tag ><br />{<br />STATIC_CONST(size_t, result, stop_tag);//Stop here!<br />};<br />/* Get the sqrt result of N*/<br />template < size_t N ><br />struct sqrt_nature<br />{<br />//STATIC_CONST(size_t, result, (sqrt_check<N, 1, N/2+1>::result));//begin searching between [1, N/2+1]<br />STATIC_CONST(size_t, result, (sqrt_check_newton<N, N/2, N>::result));<br />STATIC_CONST(bool, square, result * result == N);<br />};<br />template <><br />struct sqrt_nature< 1 ><br />{<br />STATIC_CONST(size_t, result, 1);<br />STATIC_CONST(bool, square, true);<br />};<br />template <><br />struct sqrt_nature< 0 ><br />{<br />STATIC_CONST(size_t, result, 0);<br />STATIC_CONST(bool, square, true);<br />};<br />/* Check if N % D == 0*/<br />template< size_t N, size_t D ><br />struct prime_check<br />{<br />protected:<br />STATIC_CONST(bool, mod, N % D == 0);<br />public:<br />STATIC_CONST(bool, prime, (<br />D == 1 ?<br />true : mod ?<br />false : prime_check<mod ? stop_tag : N , mod ? stop_tag : D - 1>::prime)<br />);<br />};<br />template<><br />struct prime_check< stop_tag , stop_tag ><br />{<br />STATIC_CONST(bool, prime, false);<br />};<br />/* Check if N is a prime*/<br />template< size_t N ><br />struct prime_nature<br />{<br />STATIC_CONST(bool, prime, (prime_check<N, sqrt_nature<N>::result>::prime));<br />STATIC_CONST(bool, composite, !prime);<br />};<br />template<><br />struct prime_nature<1><br />{<br />STATIC_CONST(bool, prime, false);<br />STATIC_CONST(bool, composite, false);<br />};<br />/* Get the count of prime smaller than N.*/<br />template< size_t N ><br />struct prime_count_nature<br />{<br />STATIC_CONST(size_t, prime_count, (prime_count_nature<N-1>::prime_count + (prime_nature<N>::prime ? 1 : 0)));<br />STATIC_CONST(size_t, composite_count, N - prime_count - 1);<br />};<br />template<><br />struct prime_count_nature< 1 ><br />{<br />STATIC_CONST(size_t, prime_count, 0);<br />STATIC_CONST(size_t, composite_count, 0);<br />};<br />/* The following 4 macros are used for test. You can uncomment any of 4.*/<br />#define test(x)/<br />do{/<br />if (bool(prime_nature<x>::prime))/<br />cout<<x<<endl;/<br />}while(false)<br />//#define test(x) cout<<prime_count_nature<x>::prime_count<<endl<br />//#define test(x) cout<<x<<' '<<(bool(prime_nature<x>::prime) ? "Yes" : "No")<<endl<br />//#define test(x) cout<<x<<' ' <<sqrt_nature<x>::result<<endl<br />/*Test from 1 to N*/<br />template< size_t N ><br />struct test_nature:public test_nature< N-1 ><br />{<br />test_nature():test_nature< N-1 >(){test(N);}<br />};<br />template<><br />struct test_nature< 1 ><br />{<br />test_nature(){test(1);}<br />};<br />int main()<br />{<br /> test_nature<200> x;//vc6.0 will crash for nesting template over 225<br />//test(8);<br />return 0;<br />}<br />
事實上使用enum時想濾掉那些警告也不是不行,只要你願意接受把代碼變得難懂10倍,到處充斥著莫名其妙的強制轉換,呵呵。
偷偷告訴你一個小秘密:哥的vc6標準版編譯器吐了412個警告,重新導向的檔案長達1M.
(全劇終。)
後記:哥已經休息很長時間了,最近可能又要開忙起來了。這個部落格也許很久都不會更新,有問題請留言。