C++テンプレート-value traits
2458 ワード
前の文章はtype traitsを使っていますが、実はtraitsにはvalue traitsもあります.
累積関数をもう一度見てみましょう.
この行のコードに注意してください.
traits::AccuT total = traits::AccuT();
AccuTがint,floatなどのタイプであれば,int(),float()は0に初期化されて問題ないが,万一対応するタイプが()初期化できなかったら?
このときvalue traitsを使い、int traitsを次のように変更できます.
このtraitsにはタイプと値があります.
次に、累積関数を次のように変更します.
これで初期化の問題を解決できます.そして変動があってもtraitsの中のZeroを修正するだけです.
しかし、すべてのタイプがクラスで初期化できるわけではありません.例えば、int traitsの戻り値タイプをdoubleに変更します.
このようにコンパイラは直接エラーを報告します(vs 2012)、
error C2864: 'traits::Zero' : only static const integral data members can be initialized within a class
クラスの外でこの値を初期化する人もいます.例えば、double const traits::Zero=0;これも一つの方法だ.しかし、これは良い方法ではないような気がします.より一般的にはtraits内部で静的関数を作り、静的変数ではなく関数を累積します.コード:
累積関数をもう一度見てみましょう.
template<typename T>
struct traits;
template<>
struct traits<char>
{
typedef int AccuT;
};
template<>
struct traits<int>
{
typedef int AccuT;
};
template<class T>
typename traits<T>::AccuT accum3(const T* ptr, int len)
{
traits<T>::AccuT total = traits<T>::AccuT();
for (int i = 0; i < len; i++)
{
total += *(ptr + i);
}
return total;
}
この行のコードに注意してください.
traits
AccuTがint,floatなどのタイプであれば,int(),float()は0に初期化されて問題ないが,万一対応するタイプが()初期化できなかったら?
このときvalue traitsを使い、int traitsを次のように変更できます.
template<>
struct traits<int>
{
typedef int AccuT;
static AccuT const Zero = 0;
};
このtraitsにはタイプと値があります.
次に、累積関数を次のように変更します.
template<class T>
typename traits<T>::AccuT accum3(const T* ptr, int len)
{
traits<T>::AccuT total = traits<T>::Zero;
for (int i = 0; i < len; i++)
{
total += *(ptr + i);
}
return total;
}
これで初期化の問題を解決できます.そして変動があってもtraitsの中のZeroを修正するだけです.
しかし、すべてのタイプがクラスで初期化できるわけではありません.例えば、int traitsの戻り値タイプをdoubleに変更します.
template<>
struct traits<int>
{
typedef double AccuT;
static AccuT const Zero = 0;
};
このようにコンパイラは直接エラーを報告します(vs 2012)、
error C2864: 'traits
クラスの外でこの値を初期化する人もいます.例えば、double const traits
template<typename T>
struct traits;
template<>
struct traits<char>
{
typedef int AccuT;
static AccuT const Zero = 0;
};
template<>
struct traits<int>
{
typedef double AccuT;
static AccuT Zero(){ return 0.0; };
};
template<class T>
typename traits<T>::AccuT accum3(const T* ptr, int len)
{
traits<T>::AccuT total = traits<T>::Zero();
for (int i = 0; i < len; i++)
{
total += *(ptr + i);
}
return total;
}
int _tmain(int argc, _TCHAR* argv[])
{
int sz[] = {1, 2, 3};
traits<int>::AccuT avg = accum3(sz, 3) / 3;
return 0;
}