3

C ++でマトリックス3x3クラスを書いています。

[][] operatorglm::mat3 は、構文を通じて行列データへのアクセスを提供します。
たとえばmyMatrix[0][0] = 1.0f; 、最初の行、最初の列のエントリを1.0fに設定します。

同様のアクセスを提供したいと思います。どうすれば[][] operators をオーバーロードできますか?

次のことを試しましたが、エラーが発生します。

演算子名は関数として宣言する必要があります

const real operator[][](int row, int col) const
{
    // should really throw an exception for out of bounds indices
    return ((row >= 0 && row <= 2) && (col >= 0 && col <= 2)) ? _data[row][col] : 0.0f;
}

この演算子をオーバーロードする正しい方法は何ですか?

4

5 に答える 5

7

operator は存在しない[][]ため、演算子を 2 回オーバーロードする必要があります。1[]回は行列に対して行のサロゲートオブジェクトを返し、もう 1 回は返されたサロゲート行に対して行います。

// Matrix's operator[]
const row_proxy operator[](int row) const
{
    return row_proxy(this, row);
}
// Proxy's operator[]
const real operator[](int col) const
{
    // Proxy stores a pointer to matrix and the row passed into the first [] operator
    return ((this->row >= 0 && this->row <= 2) && (col >= 0 && col <= 2)) ? this->matrix->_data[this->row][col] : 0.0f;
}
于 2012-09-30T01:03:31.850 に答える
6

メソッドを作る方が簡単でしょうdouble operator() (int row, int col) constmatrix[i][j]あなたが言う代わりにmatrix(i,j).

于 2012-09-30T01:08:36.537 に答える
5

通常、複数の引数の場合operator()、 ではなくを使用しますoperator[]

うーん、それが明らかでない場合operator[][]、C++ にはありません。operator[]2回適用しただけです。つまり、その表記法が必要な場合は、最初の表記法が 2 番目の表記法を適用できる結果 (インデックス可能なものまたはプロキシ) を返すようにする必要があります。

以下のコードは、いくつかのアプローチをスケッチしています。好きなものを選択してください。

#include <iostream>
#include <vector>

template< int n >
int& dummy() { static int elem = n; return elem; }

struct Mat1
{
    int operator() ( int const x, int const y ) const
    { return dummy<1>(); }

    int& operator() ( int const x, int const y )
    { return dummy<1>(); }

    Mat1( int, int ) {}
};

struct Mat2
{
    int at( int const x, int const y ) const
    { return dummy<2>(); }

    int& at( int const x, int const y )
    { return dummy<2>(); }

    Mat2( int, int ) {}
};

struct Mat3
{
    struct At { At( int x, int y ) {} };

    int operator[]( At const i ) const
    { return dummy<3>(); }

    int& operator[]( At const i )
    { return dummy<3>(); }

    Mat3( int, int ) {}
};

class Mat4
{
protected:
    int get( int const x, int const y ) const
    { return dummy<4>(); }

    void set( int const x, int const y, int const v ) {}

    class AssignmentProxy
    {
    private:
        Mat4*   pMat_;
        int     x_;
        int     y_;
    public:
        void operator=( int const v ) const
        { pMat_->set( x_, y_, v ); }

        int value() const { return pMat_->get( x_, y_ ); }
        operator int () const { return value(); }

        AssignmentProxy( Mat4& mat, int const x, int const y )
            : pMat_( &mat ), x_( x ), y_( y )
        {}
    };

public:
    int operator()( int const x, int const y ) const
    { return get( x, y ); }

    AssignmentProxy operator()( int const x, int const y )
    { return AssignmentProxy( *this, x, y ); }

    Mat4( int, int ) {}
};

class Mat5
{
protected:
    int at( int const x, int const y ) const
    { return dummy<4>(); }

    int& at( int const x, int const y )
    { return dummy<5>(); }

    class RowReadAccess
    {
    private:
        Mat5 const* pMat_;
        int         y_;

    public:
        int operator[]( int const x ) const
        {
            return pMat_->at( x, y_ );
        }

        RowReadAccess( Mat5 const& m, int const y )
            : pMat_( &m ), y_( y )
        {}
    };

    class RowRWAccess
    {
    private:
        Mat5*   pMat_;
        int     y_;

    public:
        int operator[]( int const x ) const
        {
            return pMat_->at( x, y_ );
        }

        int& operator[]( int const x )
        {
            return pMat_->at( x, y_ );
        }

        RowRWAccess( Mat5& m, int const y )
            : pMat_( &m ), y_( y )
        {}
    };

public:
    RowReadAccess operator[]( int const y ) const
    { return RowReadAccess( *this, y ); }

    RowRWAccess operator[]( int const y )
    { return RowRWAccess( *this, y ); }

    Mat5( int, int ) {}
};

struct Mat6
{
private:
    std::vector<int>    elems_;
    int                 width_;
    int                 height_;

    int indexFor( int const x, int const y ) const
    {
        return y*width_ + x;
    }

public:
    int const* operator[]( int const y ) const
    {
        return &elems_[indexFor( 0, y )];
    }

    int* operator[]( int const y )
    {
        return &elems_[indexFor( 0, y )];
    }

    Mat6( int const w, int const h )
        : elems_( w*h, 6 ), width_( w ), height_( h )
    {}
};

int main()
{
    using namespace std;
    enum{ w = 1024, h = 1024 };
    typedef Mat3::At At;

    Mat1 m1( w, h );
    Mat2 m2( w, h );
    Mat3 m3( w, h );
    Mat4 m4( w, h );
    Mat5 m5( w, h );
    Mat6 m6( w, h );

    wcout
        << m1( 100, 200 )       // No fuss simple, but exposes element ref.
        << m2.at( 100, 200 )    // For those who don't like operators.
        << m3[At( 100, 200)]    // If you really want square brackets mnemonic.
        << m4( 100, 200 )       // Hides element ref by using assignment proxy.
        << m5[200][100]         // Ditto but with square brackets (more complex).
        << m6[200][100]         // The minimum fuss square brackets, exposes elem ref.
        << endl;
}

コードを投稿した後、 の内部ストレージを完全に非表示にしていないことがわかりました。Mat5のように追加のプロキシ レベルが必要Mat4です。そのため、そのアプローチは非常に複雑です。私はそれをしません (Mat1簡単で良いと思います) が、一部の人々はプロキシがクールであり、データを隠すことはさらにクールだと考えています…

要約すると、オーバーロードする「その」正しい方法はありませんoperator[]。多くの方法があり (上記のコードで示されているように)、それぞれにいくつかのトレードオフがあります。また、一般的には、 を使用する方が適切です。それとoperator()は対照的に、operator[]任意の数の引数を取ることができるからです。

于 2012-09-30T02:03:33.623 に答える
3

[][]オペレーターはいません。vec3&GLM がそれを行う方法は、最初の からa を返すことです[]vec3独自の[]演算子オーバーロードがあります。つまり、operator[]2 つの別個のクラスにある 2 つの別個の です。

これは GLSL の仕組みでもあります。1 つ目[]は、列をベクトルとして取得します。2 番目はベクトルを取得し、そこから値を取得します。

于 2012-09-30T01:02:39.817 に答える
1

foo[1][2]は実際には として解釈されます。(foo[1])[2]つまり[]、変数から始まる演算子が 2 回続けて適用されますfoo[][]オーバーロードされる演算子はありません。

于 2012-09-30T01:04:23.673 に答える