C++テンプレートメタプログラミングテンプレートを使用して配列を「コンパイル期間合計」する


コンパイル期間の評価は、計算をコンパイル期間に繰り上げて行い、コンパイラの潜在力を最大限に絞り、プログラムの実行速度を向上させることができる.したがって,配列のコンパイル中に和を求める必要がある.
まずコードをつけてから説明します.
#include 
using namespace std;

//     int  ,      
const int CONST_ARRAY[5]={1,2,3,4,5};//  const   ,       

//     ,       
template
struct SumArrInCompilePhaseCls{
	static const int SUM;
};
//            SUM  
template
const int SumArrInCompilePhaseCls::SUM
			=CONST_ARRAY[index]+SumArrInCompilePhaseCls::SUM;//     

//          ,           
template<>
struct SumArrInCompilePhaseCls<0>{
	static const int SUM;
};
const int SumArrInCompilePhaseCls<0>::SUM=CONST_ARRAY[0];

int main(){
        //    ,           
	cout<::SUM<
SUMは確かにコンパイル段階で計算されたものです.SUMはstatic constタイプなので、このタイプはコンパイルが完了した後、固定され、実行中に変更できません.
上記のコードをよく検討すると、非特化型テンプレートのSUM値を定義する際に、テンプレートの再帰定義が使用されていることがわかります.
//            SUM  
template
const int SumArrInCompilePhaseCls::SUM
			=CONST_ARRAY[index]+SumArrInCompilePhaseCls::SUM;
コンパイラこの式をコンパイルする場合、SumArrInCompilePhaseClsのタイプが不明であるため、コンパイラはSumArrInCompilePhaseClsを生成し、続いてSumArrInCompilePhaseClsを生成し、SumArrInCompilePhaseClsを生成し、…まだまだたくさんあります.すなわち、この式は、コンパイラが複数のSumArrInCompilePhaseClsテンプレートクラスを再帰的に生成し、indexがついに0に減少したとき、すなわちSumArrInCompilePhaseCls<0>を生成しようとすると、コンパイラが「サプライズ」に、SumArrInCompilePhaseCls<0>が実現したことを発見する!したがって、コンパイラは「SumArrInCompilePhaseClsテンプレートクラス」の生成を停止し、再帰的に終了しました.
「SumArrInCompilePhaseClsテンプレートクラス」のSUMはすべてstatic const値であるため、const値についてはコンパイル中に和を求めることができます.
終わりましたか?
木有!
上のコードには2つの小さな問題があります.
1、呼び出し時、入力したindexが負数(例えば-1)の場合、コンパイル中に再帰スタックオーバーフローが発生し、コンパイルに失敗します.負数は「0に減らす」ことができないので、つまり、再帰は止まらない!
2、入力したindexがCONSTを超えるARRAYの上限時(例えば5)は、コンパイルが通過したにもかかわらず、コンパイル期間の合計時に配列が境界を越えたため、実行結果が間違っている!
はい、配列の和を求めるときに、ユーザーの入力が合法かどうかを判断したいと思っています.
この2つの問題は、「コンパイル中のブレークスルー」を追加することによって解決できます.このブレークスルーのソースコードは、次のとおりです.
//               ,            
template
struct CompilePhaseAssertion;

template<>
struct CompilePhaseAssertion{};

使用する場合は、次のようにします.
//     ,       
template
struct SumArrInCompilePhaseCls{
	static const int SUM;
private:
	CompilePhaseAssertion=0&&index IsValidIndex;
};
の原理は明らかでしょう?
CompilePhaseAssertionはクラステンプレートですが、定義されていません!パラメータがtrueの完全な特化バージョンが1つしかないため、テンプレートパラメータisOkがfalseの場合、isOk=falseのテンプレートクラスがないため、コンパイルエラーが発生します.
CompilePhaseAssertionでCompilePhaseAssertionインスタンスを追加することでindexの範囲が正当であることを保証します.
修正されたコードは次のとおりです.
#include 
using namespace std;

//     int  ,      
int CONST_ARRAY[5]={1,2,3,4,5};

//               ,            
template
struct CompilePhaseAssertion;

template<>
struct CompilePhaseAssertion{};

//     ,       
template
struct SumArrInCompilePhaseCls{
	static const int SUM;
private:
	CompilePhaseAssertion=0&&index IsValidIndex;
};

//            SUM  
template
const int SumArrInCompilePhaseCls::SUM
			=CONST_ARRAY[index]+SumArrInCompilePhaseCls::SUM;

//          ,           
template<>
struct SumArrInCompilePhaseCls<0>{
	static const int SUM;
};
const int SumArrInCompilePhaseCls<0>::SUM=CONST_ARRAY[0];

int main(){
	//    ,           
	cout<::SUM<

この場合、次の2つの方法で合計を求めると、コンパイルエラーが発生します.
cout<::SUM<::SUM<

本文が終わる.
参考資料:
1、《C++设计新思惟》,Andrei Alexanderescu著,侯捷,于春景訳.
2、C++テンプレートメタプログラミング技術と応用
3、栄威先生が書いた他の文章や本
4、C++のMetaProgramming入門編
注意:
以上のコードはVS 2005とG++でコンパイルできますが、G++でコンパイルされたプログラムだけが正しい結果を出すことができます(15)、VS 2005の結果は間違っています(5)、原因はまだ分かりません.