2012-09-30 119 views
2

我正在写一个矩阵3x3类在c + +。重载[] []在C++运算符

glm :: mat3通过[][] operator语法提供对矩阵数据的访问。
例如myMatrix[0][0] = 1.0f;会将第一行,第一列条目设置为1.0f

我想提供类似的访问权限。我如何超载[][] operator

我试过以下,但我得到的错误:

运营商的名称必须声明为一个函数

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; 
} 

什么是超载此操作的正确方法是什么?

+0

如果你可以处理矩阵(x,y)的语法,那就去吧。我们的代码库无法使用,因为我们希望能够使用二维数组快速交换旧代码,而不是使用我们的矩阵类。是牺牲了一些安全,但很快的一种方式达到你想要的是要做到: const的真实*运算符[](INT行)const的 { 返回_data [行]。 }; 但是,这会牺牲在获取列时对结果执行边界检查的功能,因此可以使用代理对象代替更安全的结果。 – stinky472

+0

我真的希望能够交换我的代码与GLM代码,只需通过改变使用的命名空间,所以我不能与运营商去()。 – fishfood

回答

7

没有运营商[][],所以你需要两次超载[]操作:在矩阵返回代理行一次,返回surrogate对象的行,而一旦:

// 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; 
} 
3

运营商没有[][]。 GLM的做法是从第一个[]返回vec3&vec3有自己的[]运算符超载。所以它是两个独立的课程中的两个独立的operator[]

这也是GLSL的工作原理。第一个[]将该列作为向量。第二个采用矢量并从中获取价值。

1

表达foo[1][2]实际上被解释为(foo[1])[2],即,从变量foo开始连续应用两次操作符[]。没有[][]运算符被重载。

6

制作方法double operator() (int row, int col) const会更容易。而不是matrix[i][j]你只是说matrix(i,j)

+1

http://www.parashift.com/c++-faq-lite/matrix-subscript-op.html –

5

一般来说,对于想要使用多参数operator()而不是operator[]

嗯,如果不是很明显,C++中没有operator[][]。这只是operator[]申请两次。这意味着如果你想要这个表示法,那么你必须让第一个返回第二个可以应用到的结果(可索引的东西或代理)。

下面的代码勾勒一些方法,选择你喜欢的东西:

#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是我认为的很好很容易),但有些人认为proxys很酷,数据隐藏更加酷&hellip;

总结一下,没有“ ”正确的方法来重载operator[]。有很多方法(如上面的代码所示),每个方法都有一些权衡。一般而言,’使用operator()会更好,因为与operator[]相比,它可以使用任意数量的参数。