Инициализировать ссылки на элемент матрицы в структуре - PullRequest
0 голосов
/ 16 января 2019

У меня есть структура, которая представляет трехмерную позицию. Иногда удобно получить доступ к отдельным компонентам, а иногда удобно получить доступ ко всем компонентам как к вектору (физический вектор, а не std :: vector), для которого я использую библиотеку линейной алгебры Eigen. Поскольку существует только три элемента (x, y, z) и всегда будет только три элемента, есть ли что-то не так в структуре, имеющей три double&, которые относятся к элементам Собственной матрицы? i.e.:

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

Он прекрасно компилируется без предупреждений на g ++ 5.5 с -Wall -Wextra -pedantic в тех случаях, когда я могу придумать:

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

Как я уже сказал, это работает, мне просто любопытно, если это законно и не полагается на неопределенное поведение и т. Д. Или есть другие вопросы, которые нужно знать?

1 Ответ

0 голосов
/ 18 января 2019

После добавления назначения копирования ваш код должен быть в безопасности.

Однако, если вы в порядке с написанием 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 в качестве члена.

...