2D 矩阵和重载operator()/丑陋的语法

发布于 2024-07-16 15:03:03 字数 585 浏览 4 评论 0原文

我在我的一个项目中使用二维矩阵。 这就像 C++ FAQ Lite。

巧妙的是,您可以像这样使用它:

int main()
{
  Matrix m(10,10);
  m(5,8) = 106.15;
  std::cout << m(5,8);
  ...
}

现在,我有一个由顶点组成的图,每个顶点都有一个指向 2D 矩阵的公共(只是为了简单起见)指针,如上所示。 现在我确实有一个非常丑陋的语法来访问它。

(*sampleVertex.some2DTable)(0,0) = 0; //bad
sampleVertex.some2DTable->operator()(0,0) = 0; //even worse...

由于我对运算符重载缺乏经验,可能我在这里缺少一些语法糖。 有更好的解决方案吗?

I'm using a 2D matrix in one of my projects. It's something like it is suggested at C++ FAQ Lite.

The neat thing is that you can use it like this:

int main()
{
  Matrix m(10,10);
  m(5,8) = 106.15;
  std::cout << m(5,8);
  ...
}

Now, I have a graph composed of vertices and each vertex has a public (just for simplicity of the example) pointer to 2D matrix like above. Now I do have a pretty ugly syntax to access it.

(*sampleVertex.some2DTable)(0,0) = 0; //bad
sampleVertex.some2DTable->operator()(0,0) = 0; //even worse...

Probably I'm missing some syntactic sugar here due to my inexperience with operator overloading. Is there a better solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

凉城凉梦凉人心 2024-07-23 15:03:03
  1. 考虑使用引用而不是指针(前提是它不能为 null 并且可以在构造函数中初始化)。
  2. 考虑为顶点创建一个 getter 或矩阵包装类的实例,以返回对 2D 矩阵的引用(前提是它不能为 null)。

    sampleVertex.some2DTable()(0,0) = 0; 
      SampleVertex.some2DTableWrap(0,0) = 0; 
      

然而,对我来说,这听起来并不是什么问题,足以证明经历所有麻烦是合理的。

  1. Consider using references instead of pointers (provided, it can't be null and you can initialize in the constructor).
  2. Consider making a getter or an instance of a matrix wrapper class for a vertex that returns a reference to 2D matrix (provided, it can't be null).

    sampleVertex.some2DTable()(0,0) = 0;
    sampleVertex.some2DTableWrap(0,0) = 0;
    

However, to me it sounds like a non-issue to justify going through all the trouble.

花开柳相依 2024-07-23 15:03:03

如果您有一个指向 Matrix 的指针,例如作为无法引用的函数参数(例如遗留代码),您仍然可以对其进行引用(伪代码):

struct Matrix {
        void operator () (int u, int v) {
        }
};
int main () {
        Matrix *m;
        Matrix &r = *m;
        r (1,1);
}

If you have a pointer to a Matrix, e.g. as a function parameter that you can't make a reference (legacy code, e.g.), you can still make a reference to it (pseudo code):

struct Matrix {
        void operator () (int u, int v) {
        }
};
int main () {
        Matrix *m;
        Matrix &r = *m;
        r (1,1);
}
拿命拼未来 2024-07-23 15:03:03

您基本上仅限于 (*sampleVertex.some2DTable)(0,0)。 当然,如果您不需要重新设置,为什么不将实际值存储在矩阵中呢?

或者,将指针设置为私有并创建一个访问器(注意:以下示例假设 EntryTypes 矩阵):

Matrix& Vertex::GetTableRef() 
{
    return *some2DTable; 
}
// or
Matrix::EntryType& Vertex::GetTableEntry(int row, int col)
{
    return (*some2DTable)(row,col);
}

// way later...
myVertex.GetTableRef()(0,0) = 0;
// or...
myVertex.GetTableEntry(0,0) = 0;

或者,如果您无法更改类 Vertex,只需定义一个内联函数来为您执行此操作:

// in some header file
inline Matrix& GetTableRef(Vertex& v)
{
    return *v.some2DTable;
}

// or you could do this
inline Matrix::EntryType& GetTableEntry(Vertex& v, int row, int col)
{
    return (*v.some2DTable)(row, col);
}


// later...
GetTableRef(myVertex)(0, 0) = 0;
// or
GetTableEntry(myVertex, 0, 0) = 0;

最后,不要忘记您没有必须使用运算符重载。 STL 集合实现了 at() 成员函数,该函数是经过检查的,而不是operator[] 是未经检查的。 如果您不介意边界检查的开销,或者只是想要非标准,则可以实现 at() ,然后只需调用 myVertex.some2DTable->at(0,0) ,完全避免了一些令人头痛的语法问题。

You're basically limited to (*sampleVertex.some2DTable)(0,0). Of course, if you don't need reseating, why not store the actual values in the matrix instead?

Alternatively, make the pointer private and make an accessor (note: the following examples assume a matrix of EntryTypes):

Matrix& Vertex::GetTableRef() 
{
    return *some2DTable; 
}
// or
Matrix::EntryType& Vertex::GetTableEntry(int row, int col)
{
    return (*some2DTable)(row,col);
}

// way later...
myVertex.GetTableRef()(0,0) = 0;
// or...
myVertex.GetTableEntry(0,0) = 0;

Or, just define an inline function to do this for you if you can't change the class Vertex:

// in some header file
inline Matrix& GetTableRef(Vertex& v)
{
    return *v.some2DTable;
}

// or you could do this
inline Matrix::EntryType& GetTableEntry(Vertex& v, int row, int col)
{
    return (*v.some2DTable)(row, col);
}


// later...
GetTableRef(myVertex)(0, 0) = 0;
// or
GetTableEntry(myVertex, 0, 0) = 0;

Finally, don't forget that you don't have to use operator overloading. STL collections implement an at() member function, which is checked, as opposed to operator[] which is unchecked. If you don't mind the overhead of bounds checking, or if you just want to be nonstandard, you could implement at() and then just call myVertex.some2DTable->at(0,0), saving a bit of a syntactic headache altogether.

这样的小城市 2024-07-23 15:03:03

没有 C++ 语法糖可以减轻您所描述的痛苦:

(*sampleVertex.some2DTable)(0,0) = 0; //bad
sampleVertex.some2DTable->operator()(0,0) = 0; //even worse...

在这种情况下,我要么让图形返回引用而不是指针,要么让矩阵定义一个调用 operator() 的函数:

inline matrixType &Matrix::get( int x, int y ){ return operator()(x,y); }

然后,对于顶点示例来说,语法并不那么难看:

sampleVertex.some2DTable->get(0,0) = 0;

There is no C++ syntactic sugar that will ease the pain of what you describe:

(*sampleVertex.some2DTable)(0,0) = 0; //bad
sampleVertex.some2DTable->operator()(0,0) = 0; //even worse...

In this situation, I would either have the graph return a reference instead of a pointer, or have the matrix define a function which calls the operator():

inline matrixType &Matrix::get( int x, int y ){ return operator()(x,y); }

Then, the syntax isn't quite as ugly for the vertex example:

sampleVertex.some2DTable->get(0,0) = 0;
有深☉意 2024-07-23 15:03:03

我会添加一个函数,返回一个像 rlbond 推荐的 ref 。 为了快速修复或者如果您无法控制它的源,我会这样做:

sampleVertex.some2DTable[0](0,0) = 0; // more readable

这实际上是等效的,因为如果 a 是指向已定义类的指针,则以下内容成立:

*a == *(a + 0) == a[0]

请参阅comp.lang.c++ 上关于同一问题的长讨论,并给出了很好的答案。

I would add a function that returns you a ref like rlbond recommends. For a quick fix or if you don't have control over the source of it, i would go with this:

sampleVertex.some2DTable[0](0,0) = 0; // more readable

That's actually equivalent, because the following holds if a is a pointer to a defined class:

*a == *(a + 0) == a[0]

See this long discussion on comp.lang.c++ about that same problem with good answers.

遥远的她 2024-07-23 15:03:03

这是无需更改代码的最佳方法:

//some2DTable is a pointer to a matrix
(*sampleVertex.some2DTable)(0,0)

您还可以将 some2DTable 设为对矩阵的引用,而不是指向矩阵的指针。 然后,您将获得简化的语法,如第一个代码片段中所示。

//some2DTable is a reference to a matrix instead of a pointer to a matrix
sampleVertex.some2DTable(0,0)

或者,您可以保留 some2DTable 一个指向引用的指针,并简单地将引用变量存储到它并在代码块的上下文中使用它。

This is the best way without changing your code:

//some2DTable is a pointer to a matrix
(*sampleVertex.some2DTable)(0,0)

You could also instead make some2DTable a reference to a matrix instead of a pointer to a matrix. Then you would have simplified syntax as in your first code sniplet.

//some2DTable is a reference to a matrix instead of a pointer to a matrix
sampleVertex.some2DTable(0,0)

Or you could keep some2DTable a pointer to a reference and simply store a reference variable to it and use that in the context of your code block.

執念 2024-07-23 15:03:03

我会改变您获取“sampleVertex.some2DTable”的方式,以便它返回一个引用。

要么这样,要么自己创建参考:

Matrix& m = *sampleVertex.some2DTable;
m(1,2) = 3;

I'd change the way you get hold of "sampleVertex.some2DTable" so it returns a reference.

Either that or create the reference yourself:

Matrix& m = *sampleVertex.some2DTable;
m(1,2) = 3;
迷离° 2024-07-23 15:03:03

我不知道这是否值得这么麻烦,但你可以这样做:

class MatrixAccessor {
private:
  Matrix2D* m_Matrix;
public:
  MatrixAccessor(Matrix2D* matrix) : m_matrix(matrix) { }
  double& operator()(int i, int j) const { return (*m_Matrix)(i,j); }
  Matrix2D* operator->() const { return m_Matrix; }
  void operator=(Matrix2D* matrix) { m_Matrix = matrix; }
};

假设原始的operator()返回一个引用(就像在许多矩阵类中一样)。

然后,您在顶点类中提供该 MatrixAccessor:

class Vertex {
  Matrix2D* myMatrix;

public:
  MatrixAccessor matrix;
  Vertex(Matrix2D *theMatrix) : myMatrix(theMatrix), matrix(theMatrix) { }
};

然后您可以编写:

Vertex v;
v.matrix(1,0) = 13;
v.matrix->SomeOtherMatrixOperation();

编辑

我添加了 const 关键字(感谢 @phresnel 提出topic),以使解决方案在语义上等同于仅呈现公共 Matrix2D 指针的解决方案。

此解决方案的一个优点是,可以通过添加两个非 const 版本的operator()() 和operator-> 将常量转移到矩阵对象;()(即矩阵不能在 const 顶点上修改)并更改 const 顶点以返回 const double&和 const Matrix2D* 分别。

当使用指向矩阵对象的公共指针时,这是不可能的。

I don't know if it's worth the trouble, but you could do:

class MatrixAccessor {
private:
  Matrix2D* m_Matrix;
public:
  MatrixAccessor(Matrix2D* matrix) : m_matrix(matrix) { }
  double& operator()(int i, int j) const { return (*m_Matrix)(i,j); }
  Matrix2D* operator->() const { return m_Matrix; }
  void operator=(Matrix2D* matrix) { m_Matrix = matrix; }
};

Provided the original operator() returns a reference (as it is in many matrix classes).

Then you provide that MatrixAccessor in your vertex class:

class Vertex {
  Matrix2D* myMatrix;

public:
  MatrixAccessor matrix;
  Vertex(Matrix2D *theMatrix) : myMatrix(theMatrix), matrix(theMatrix) { }
};

Then you can write:

Vertex v;
v.matrix(1,0) = 13;
v.matrix->SomeOtherMatrixOperation();

EDIT

I added const keywords (thanks to @phresnel for bringing up the topic) in order to make the solution semantically equivalent to a solution only presenting a public Matrix2D-pointer.

An advantage of this solution is that constness could be transferred to the matrix object by adding two non-const versions of the operator()() and operator->() (i.e. the matrix cannot be modified on const vertices) and changing the const ones to return a const double& and const Matrix2D* respectively.

That would not be possible when using a public pointer to the matrix object.

遥远的她 2024-07-23 15:03:03

您可以通过调用成员函数来实现 Matrix::operator (int,int) 并在处理指针时直接使用该函数。

class Matrix
{
public:
  float ElementAt( int i, int j ) const { /*implement me*/ }
  float operator() ( int i, int j ) const { return ElementAt( i, j ); }
  ...
};

void Foo(const Matix* const p)
{
  float value = p->ElementAt( i, j );
  ...
}

void Bar(const Matrix& m)
{
  float value = m(i,j);
}

You could implement Matrix::operator (int,int) by calling a member function and use that one directly when dealing with pointers.

class Matrix
{
public:
  float ElementAt( int i, int j ) const { /*implement me*/ }
  float operator() ( int i, int j ) const { return ElementAt( i, j ); }
  ...
};

void Foo(const Matix* const p)
{
  float value = p->ElementAt( i, j );
  ...
}

void Bar(const Matrix& m)
{
  float value = m(i,j);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文