home > programming > notes >

テンプレート小物集

学習目的と思いつきで作ってみたテンプレートを紹介します。使えないものばかりですが。

セーフリリース

DirectXではポインタからRelease()メソッドで明示的に解放しなくてはならないオブジェクトが多いので、そういうオブジェクトの解放を簡素化します。ラッパクラスのデストラクタに書くと効果的です。マクロでも同じことが出来ますが、テンプレートのほうが安全です。

template <class T>
void SafeRelease(T*& p)
{
    if (p)
    {
        p->Release();
        p = NULL;
    }
}

絶対値

絶対値を返却。はっきり言っていらないですが。

template <class T>
T Abs(T n)
{
    return ((n < 0) ? -n : n);
}

累乗

引数を整数乗します。たとえばxを2乗したいときはPow<2>(x)。

長い計算式の結果を累乗するときに、書くのが楽になります。他の用途には役に立ちません。マイナス乗もできません。

部分特殊化が出来ないVisualC++6.0用のソースなので無駄に長いです。

namespace Private {

template <int p>
struct Pow_a
{
    template <class T>
    static T Pow_b(const T& val)
    {
        return val * Pow_a<p - 1>::Pow_b(val);
    }
};

template <>
struct Pow_a<1>
{
    template <class T>
    static T Pow_b(const T& val)
    {
        return val;
    }
};

template <>
struct Pow_a<0>
{
    template <class T>
    static T Pow_b(const T& val)
    {
        return 1;
    }
};

}   //namespace Private

template <int p, class T>
T Pow(const T& val)
{
    return Private::Pow_a<p>::Pow_b(val);
}

自動比較演算子クラス

面倒臭い比較演算子を追加するテンプレートクラス。

class A : public AutoComparisonOperators<A>
{
    virtual bool operator < (const A& r) const
    {
        //オーバーライド処理
    }
};

のようにして使います。operator<をオーバーライドすれば他の比較演算子も使えるようになります。operator==も等値で判断したい場合はオーバーライドします。まあ、速度のことを考えたら、使わないほうが良いクラスです。

template <class T>
class AutoComparisonOperators
{
public:
    virtual bool operator < (const T& r) const = 0;

    bool operator > (const T& r) const
    {
        return r.operator < (*this);
    }

    bool operator <= (const T& r) const
    {
        return !(r.operator < (*this));
    }

    bool operator >= (const T& r) const
    {
        return !(operator < (r));
    }

    virtual bool operator == (const T& r) const
    {
        return ((!(operator > (r))) && (!(operator < (r)));
    }

    bool operator != (const T& r) const
    {
        return !(operator == (r));
    }
};

ループカウンタクラス

ループカウンタ用のクラス。一定数カウントすると0に戻ります。

これはテンプレート引数の部分特殊化を使ったバージョンです。

struct EmptyType
{};

template<unsigned int Max, class Son = EmptyType>
class LoopCounter
{
protected:
    Son             m_Son;
    unsigned int    m_Count;
public:
    LoopCounter() : m_Count(0) {}
    operator unsigned int() { return m_Count; }
    LoopCounter& operator++()
    {
        if (++m_Son == 0)
        {
            if (++m_Count == Max)
            {
                m_Count = 0;
            }
        }
        return *this;
    }
    Son& GetSon() { return m_Son; }
};

template<unsigned int Max>
class LoopCounter<Max, EmptyCounter>
{
protected:
    unsigned int    m_Count;
public:
    LoopCounter() : m_Count(0) {}
    operator unsigned int() { return m_Count; }
    LoopCounter& operator++()
    {
        if (++m_Count == Max)
        {
            m_Count = 0;
        }
        return *this;
    }
};

特徴として、子を持つことができるので

LoopCounter<10, LoopCounter<10> > AnimationCounter;

のようにすれば、

++AnimationCounter;

を実行するたびに子カウンタがインクリメントされ、10回インクリメントされると親カウンタの値が変化します。一定フレームごとにパターンを切り替えるアニメ処理などに使えます。親をインクリメントすると子がインクリメントされるのが少し気持ち悪いですが。それと、テンプレートなので定数でしか作れないのが最大の弱点です。