初始化对结构中矩阵元素的引用

Initialize references to matrix element in struct

我有一个表示 3D 位置的结构。有时访问单个组件很方便,有时访问所有组件作为向量(物理向量不是 std::vector)很方便,我正在为此使用 Eigen 线性代数库。由于只有三个元素 (x, y, z) 并且永远只会是三个元素,因此具有三个 double& 的结构是否有任何问题,这些 double& 是指本征矩阵的元素?即:

using ColumnVector3 = Eigen::Matrix<double, 3, 1>;

struct EnuPosition
{
  EnuPosition(): pos(ColumnVector3::Zero()), east(pos[0]), north(pos[1]), up(pos[2]) {}

  EnuPosition(double east, double north, double up): pos((ColumnVector3() << east, north, up).finished()),
    east(pos[0]), north(pos[1]), up(pos[2]) {}

  EnuPosition(const ColumnVector3& position): pos(position), east(pos[0]), north(pos[1]), up(pos[2]) {}

  EnuPosition(const EnuPosition& enu):pos(enu.pos), east(pos[0]), north(pos[1]), up(pos[2]) {}

  EnuPosition& operator=(const EnuPosition& enu)
  {
    this->pos = enu.pos;
    return *this;  
  }

  ColumnVector3 pos;
  double& east;
  double& north;
  double& up;
};

在我能想到的用例中 -Wall -Wextra -pedantic,它在 g++ 5.5 上没有警告编译得很好:

int main ()
{
  EnuPosition enu{12.5, 34.2, 99.2};
  std::cout << "east: " << enu.east
        << " north: " << enu.north 
        << " up: " << enu.up
        << std::endl;

  ColumnVector3 x;
    x << 2.0,3.0,4.0;

  enu.pos = x;

  std::cout << "east: " << enu.east
        << " north: " << enu.north 
        << " up: " << enu.up
        << std::endl;

  Eigen::MatrixXd y;
  y.resize(3,1);

  y << 7.6,8.7,9.8;

  enu.pos = y;

  std::cout << "east: " << enu.east
      << " north: " << enu.north 
      << " up: " << enu.up
      << std::endl;

  Eigen::Matrix<double,3,3> R;

  enu.east = 1;
  enu.north = 1;
  enu.up = 1;

  R << 1,2,3,4,5,6,7,8,9;

  enu.pos = (R * enu.pos).eval();

  std::cout << "east: " << enu.east
    << " north: " << enu.north 
    << " up: " << enu.up
    << std::endl;

  EnuPosition enu2 = enu;
  std::cout << "east: " << enu2.east
    << " north: " << enu2.north 
    << " up: " << enu2.up
    << std::endl;
}

就像我说的,它有效,我只是好奇它是否合法并且不依赖于未定义的行为等。或者还有其他需要注意的问题?

添加复制分配后,您的代码应该是安全的。

但是,如果您可以在代码中编写 east() 而不是 east,那么一个稍微更优雅的解决方案可能是这样的:

using ColumnVector3 = Eigen::Matrix<double, 3, 1>;

struct EnuPosition : public ColumnVector3
{
  EnuPosition(): ColumnVector3(ColumnVector3::Zero()) {}

  EnuPosition(double east, double north, double up): ColumnVector3(east, north, up) {}
  template<class X> 
  EnuPosition(const X& other): ColumnVector3(other) {}

  double&       east()        {return this->x();}
  double const& east() const  {return this->x();}
  double&       north()       {return this->y();}
  double const& north() const {return this->y();}
  double&       up()          {return this->z();}
  double const& up() const    {return this->z();}
};

如果你有意不想继承,你当然仍然可以将 ColumnVector3 存储为成员。