C++ templateで線形対数クラスを作る

何の記事を書くか迷ったけど、先ず復習からということで。

Embeded環境でtemplateは書けない、と思ってたら何故かコンパイルが通ってしまったので、調子にのってC++ templateを久々に書いてみた。以前は弾かれたので不思議である。
 対象としては、ちょうど線形対数関連でまとまったものが無かったので、OpenCVを参考に(というか他の人も違和感無く使えるように意図的に似せて)Vectorを扱えるものにしたのでそのメモを。最新は4.4.0だが、CV::Matが結構イケてて2.1でも勉強になる。


線形対数関連をまとめて作りたかったので、Vectorの前にMatrixから。

/**
@brief    行列クラス
@param    T    データ型
@param    r    行
@param    c    列
*/
template<class T, int r, int c>
class Matricx{
public:
    //define
    enum{ rows = r; cols = c; };
    typedef T value_type;
    typedef Matric<T, r, c> type;

protected:
    //Variable
    T data[rows * cols];  //1次元配列    

public:
    //Constructor
    Matrix();
            
    //operator
    Matrix<T, r, c> operator+ (T src);
    Matric<T, r, c> operator+ (Matrix<T, r, c> src);
    
    //Function
    virtual T at(r, c);
};

面倒くさいので演算子などは一部しか書かないが、折角なので書いた分は全部解説する。

/**
@brief    行列クラス
@param    T    データ型
@param    r    行
@param    c    列
*/

クラスの説明のコメント。Doxygenで読み込んで資料を自動生成できるフォーマットなので、まぁまぁ便利。使わなくてもこれがあるのと無いのとで解読にかかる時間が大幅に変わるので皆書いて早く帰ろう。
 中途半端なまとめ記事を読むぐらいなら公式ドキュメント読んだ方が楽なので、一応公式 (JPN) へのリンクも。

template<class T, int r, int c>
class Matricx{
…
}

括弧{...}内がtemplate classですよ、って宣言。これの種類別にコンパイラがコードを生成するらしい。

public:
protected:

外部公開レベル。publicなら全公開、protectedなら内部公開。他にもprivateがあるけど、継承先で使えないのであまり使ったことは無い。

    //define
    enum{ rows = r; cols = c; };
    typedef T value_type;
    typedef Matric<T, r, c> type;

コンパイル時定数。ここでtypedefも扱える上に変数みたいな扱いができるので、if(val1.type == val2.type)みたいな比較ができそうで便利そう。

    //Variable
    T data[rows * cols];  //1次元配列  

先程定義したrows, colsと組み合わせることで、mallocとかnewを使わなくても可変長配列(コンパイル時に決定するものに限る)が実装できるらしい。天才か。

    //Constructor
    Matrix();
            
    //operator
    Matrix<T, r, c> operator+ (T src);
    Matric<T, r, c> operator+ (Matrix<T, r, c> src);

コンストラクタおよび演算子。消すのは電源断時に限るのでデストラクタは不要。コンストラクタおよび演算子も(ヘッダ内の)外部に記述できることにちょっと感動した。ただし記述はかなり長くなる。

//宣言の後
   
template<class T, r, c> inline
Matrix<T, r, c> Matrix<T, r, c>::operator+ (T src){
    /*ここに実装を書く*/
}
template<class T, r, c> inline
Matric<T, r, c> Matrix<T, r, c>::operator+ (Matrix<T, r, c> src){
    /*ここに実装を書く*/
}

必要なものはまだまだあるが、必要に応じて実装するものとする。

    //Function
    virtual T at(r, c);    //指定された成分を取り出す

関数。データに直接アクセスできないようにしたので、getterとして必要。Virtualとあるのは、継承先で同名の関数を利用できるようにするため。

長くなったが、Matrixを継承してVectorを定義する。ここではcol (列)  = 1の縦ベクトルでいく。

/**
@brief    ベクトルクラス
@param    T    データ型
@param    r    行
*/
template<class T, int r>
class Vector : public Matricx<T, r, 1>{
public:
    //Function
    T at(r);    //指定された成分を取り出す
}

行列を定義していたため、その特殊型であるベクトルの定義は一瞬で終わった。強いて言うなら、列成分を引数にとる関数を再定義することぐらいだろうか。


数年ぶりにtemplateを書いたのでイマイチなところがあるかもしれない。はやく仕事用PCにVS Code導入して補完とか色分けとかしたい。



この記事が気に入ったらサポートをしてみませんか?