Можно ли получить ссылку на строку матрицы?

У меня есть следующий код, который использует библиотеку Eigen C++.

void myFunc(Eigen::MatrixXf& myrow)
{

  myrow.setOnes();
}



int main()
{


  Eigen::MatrixXf A(2,3);
  Eigen::MatrixXf tmp1(1,3);
  myFunc(tmp1);
  A.row(1) = tmp1;
  std::cout<<"A is..\n"<<A<<std::endl;
  return 0;

}

Как видите, для управления строками матрицы А я использовал временную переменную «tmp1». Можно ли это сделать без использования какой-либо временной переменной? Я не хочу передавать всю матрицу "А" в функцию как параметр. Обратите внимание, что «myFunc» — это всего лишь пример, мне, возможно, придется делать некоторые сложные вещи внутри функции, чтобы манипулировать строками «A». Также обратите внимание, что иногда я хотел бы вызвать «myFun», как показано в примере. Поэтому мне нужно решение, которое будет работать в обоих случаях.


person Soo    schedule 27.11.2016    source источник
comment
Это может помочь: stackoverflow.com/a/13915065/951890   -  person Vaughn Cato    schedule 27.11.2016
comment
Есть ли причина не использовать Eigen::Ref<VectorXf> ?   -  person billx    schedule 29.11.2016


Ответы (3)


Eigen поддерживает блочные выражения, которые ссылаются на подматрицу в данной матрице. Вы можете передать этот блок непосредственно в свою функцию:

void myFunc(Eigen::MatrixXf::RowXpr myrow)
{
    myrow.setOnes();
}

...
myFunc(A.row(1));

Выражение блокировки: Block.

person Nico Schertler    schedule 27.11.2016
comment
Спасибо за ваш ответ. Да. Это решает проблему, которую я опубликовал. Но теперь пример кода, который я разместил, дает ошибку компиляции. Проблема в том, что myFunc теперь ожидает ссылку. Иногда я хотел бы вызвать myFun, как показано в примере. Пожалуйста, смотрите мой отредактированный пост. - person Soo; 28.11.2016
comment
Вы все еще можете пройти tmp1.row(0). Вы также можете определить перегрузку для общей однострочной матрицы, которая сделает это за вас. Или используйте шаблон, как предложил Ави. - person Nico Schertler; 28.11.2016
comment
@Avi Да, tmp1.row(0) всегда доступен. Думаю, у меня получилось лучше, импровизируя ответ Ави. Пожалуйста, проверьте это и прокомментируйте. - person Soo; 28.11.2016

Вы можете создать шаблон функции в ответе Нико следующим образом:

template<typename Derived>
void myFunc(Eigen::MatrixBase<Derived>& m)
{
    m.setOnes();
}

int main()
{
    Eigen::MatrixXf A(2, 3);
    Eigen::MatrixXf tmp1(1, 3);
    myFunc(tmp1);
    A.row(1) = tmp1;
    std::cout << "A is..\n" << A << std::endl;

    myFunc(A.row(0));
    std::cout << "A is..\n" << A << std::endl;

    return 0;
}
person Avi Ginsburg    schedule 28.11.2016
comment
@Nico Ошибка компиляции для myFunc(A.row(0)); ошибка: недопустимая инициализация неконстантной ссылки типа «Eigen::MatrixBase‹Eigen::Block‹Eigen::Matrix‹float, -1, -1›, 1, -1, false› ›&» из rvalue type 'Eigen::DenseBase‹Eigen::Matrix‹float, -1, -1› ›::RowXpr {aka Eigen::Block‹Eigen::Matrix‹float, -1, -1›, 1, -1, false›}' myFunc(A.row(0)); ^ test.cpp: 19: 6: ошибка: при передаче аргумента 1 'void myFunc (Eigen:: MatrixBase‹Derived›&) [с Derived = Eigen::Block‹Eigen::Matrix‹float, -1, -1 ›, 1, -1, false›]' void myFunc(Eigen::MatrixBase‹Derived›& m) - person Soo; 28.11.2016
comment
Вы правы. Я тестировал его на VS2015, и из-за нестандартной привязки r-значения к ссылке l-значения это сработало. Сбой с gcc. - person Avi Ginsburg; 28.11.2016

Импровизируя ответ Ави, я получил следующий код. На самом деле мы обманываем компилятор и удаляем "const" внутри "myFunc". Я не уверен, является ли это чистым методом, а также не уверен в какой-либо цене производительности для этого метода.

template<typename Derived>
void myFunc(Eigen::MatrixBase<Derived> const& m)
{
    Eigen::MatrixBase<Derived>& m_dummy = const_cast<Eigen::MatrixBase<Derived>& > (m);
    m_dummy.setOnes();
}

int main()
{
    Eigen::MatrixXf A(2, 3);
    Eigen::MatrixXf tmp1(1, 3);
    myFunc(tmp1);
    A.row(1) = tmp1;
    std::cout << "A is..\n" << A << std::endl;

    myFunc(A.row(0));
    std::cout << "A is..\n" << A << std::endl;

    return 0;
}
person Soo    schedule 28.11.2016
comment
Нет, не делай этого. Ваша подпись обещает звонящему не изменять m, но на самом деле это делаете вы. Если вы хотите изменить m, не передавайте его как const. Никогда не используйте const_cast, если вы действительно не знаете, что делаете. Именно это и сделал Ави в своем ответе - person Nico Schertler; 28.11.2016
comment
@Нико Да, я согласен с тобой. Однако только сейчас я обнаружил, что Eigen Documentation предлагает такой метод. См. Eigen_Doc и комментарии. Также обратите внимание, что ответ Ави приводит к ошибке компиляции. - person Soo; 28.11.2016
comment
Ну просто ужасно. Лучшим способом было бы скопировать вещи во временную матрицу. В любом случае, сценарий в документе Eigen отличается от вашего. В вашем случае литье не нужно. - person Nico Schertler; 28.11.2016
comment
Здесь главная цель — избегать временных объектов! - person Soo; 28.11.2016
comment
Вот почему в вашем случае const-casting не нужен! - person Nico Schertler; 28.11.2016