Ошибка компиляции Использование шаблонного программирования с библиотекой Eigen C++

Я скачал библиотеку Eigen (3) и начал ее использовать. Я написал функцию-шаблон и объявил внутри функции локальную переменную «типа шаблона». Я получаю следующую ошибку компиляции.


$ g++ EigenTest.cpp

EigenTest.cpp: In instantiation of ‘void myFunc(Eigen::MatrixBase<Derived>&) [with Type1 = Eigen::Matrix<double, -1, -1>]’:
EigenTest.cpp:24:10:   required from here
EigenTest.cpp:16:26: error: conversion from ‘Eigen::DenseCoeffsBase<Eigen::Matrix<double, -1, -1>, 1>::Scalar {aka double}’ to non-scalar type ‘Eigen::Matrix<double, -1, -1>’ requested
   Type1 tmp = matrix(0, 0);

«EigenTest.cpp» приведен ниже.


#include "Eigen/Dense"

#include <iostream>

template<typename Type1>
void myFunc(Eigen::MatrixBase<Type1>& matrix)
{
int i=matrix.rows();
Type1 tmp = matrix(0, 0);           // getting compiler error here
std::cout<<"tmp is ->"<<tmp<<std::endl;
}

int main()
{
Eigen::MatrixXd m(2,2);
m.setConstant(100); 
myFunc(m);
return 0;
}

Я также пробовал использовать 'typename Type1 tmp = matrix(0, 0);'
Это тоже не сработало!

Как это исправить? В обычном шаблонном программировании на C++ (без Eigen) я могу определить локальную переменную внутри функции шаблона как «Type1 tmp;»


person Sooraj    schedule 31.10.2013    source источник
comment
Что такое Type1? И программа, которую вы показываете в вопросе, не та, которая выдавала ошибки. Пожалуйста, покажите настоящую программу.   -  person Some programmer dude    schedule 31.10.2013
comment
Извините, что пропустил часть кода в начальном сообщении. Type1 на самом деле является «имя типа шаблона»   -  person Sooraj    schedule 31.10.2013
comment
Проще говоря, похоже, что возврат от вызова matrix(0, 0) (что я не совсем понимаю, но это рано) не соответствует типу Type1 - что бы это ни было, вы не показали нам, как определяется Type1, предположительно где-то в каком-то typedef.   -  person Grimm The Opiner    schedule 31.10.2013
comment
Я предлагаю вам узнать, что такое SSCCE.   -  person Some programmer dude    schedule 31.10.2013
comment
Ребята, код отсутствовал <>, теперь я получаю ошибку, как описано в ОП.   -  person rubenvb    schedule 31.10.2013


Ответы (3)


В Eigen::MatrixBase<Type1> Type1 — это не скалярный тип, а тип фактического выражения. В вашем примере это будет MatrixXd, но если myFunc вызывается, например, m.block(...), то Type1 будет Block‹...>. Чтобы получить скалярный тип, вы можете использовать Type1::Scalar:

template<typename Type1>
void myFunc(Eigen::MatrixBase<Type1>& matrix)
{
  typename Type1::Scalar Scalar;
  Scalar tmp = matrix(0, 0);
}

И если вам нужен тип матрицы, похожий на Type1, используйте Type1::PlainObject, например:

typename Type1::PlainObject mat = 2 * matrix * matrix.transpose();
person ggael    schedule 31.10.2013
comment
Спасибо за ответ. Как вы предложили, я использовал Type1::Scalar, и теперь он работает. - person Sooraj; 01.11.2013
comment
я думаю, что нижний код должен быть Type1::PlainObject, а не PlainObjectType - person ofloveandhate; 15.04.2016
comment
@ofloveandhate, вы правы, я обновил ответ. - person ggael; 15.04.2016

Похоже, что MatrixBase использует "CRTP" (см. здесь), аргумент шаблона на самом деле является типом вытекающие из него. Таким образом, при использовании вами метода myFunc() Type1 фактически представляет Eigen::MatrixXd, и я думаю, что вы считаете Type1 двойным. Итак, эта строка:

Type1 tmp = matrix(0, 0);

В документации к этой библиотеке (см. здесь) typedef для MatrixXd представляет собой матрицу двойников , поэтому я предполагаю, что возврат из matrix(0, 0) является двойным, а поскольку tmp имеет значение Type1, которое равно Eigen::MatrixXd, одно не войдет в другое.

Сканируя документацию, я думаю, что вашей функции МОЖЕТ быть лучше использовать Matrix в качестве аргумента, чтобы скалярный тип был доступен. Что-то вроде этого:

template<class T, int rows, int cols, int opts, int maxR, int maxC > 
void myFunc( Eigen::Matrix<T, rows, cols, opts, maxR, maxC>& matrix )
{
    T tmp = matrix(0, 0);
}

(Выглядит ужасно, хотя!!! ;-))

person Grimm The Opiner    schedule 31.10.2013
comment
Хорошо, вывод ошибок вводит в заблуждение еще больше, чем я думал. Разве вы не можете использовать это, чтобы получить базовый тип данных? - person rubenvb; 31.10.2013
comment
Не совсем заблуждение. В сообщении об ошибке Eigen::DenseCoeffsBase<Eigen::Matrix<double, -1, -1>, 1>::Scalar ссылается на double (в вашем случае), а затем сообщение продолжается, что оно не может превратить это в Eigen::Matrix<double, -1, -1>, то есть Type1, тип, производный от MatrixBase, а также параметр шаблона. Просто! (Нет!) Насчет другого решения, вполне может быть - я не знаю эту библиотеку, просто быстро просмотрел документацию на предмет источника ошибки. - person Grimm The Opiner; 31.10.2013
comment
Это может быть один из тех случаев, когда MSVC может просто выдать самую полезную ошибку (поскольку он обычно перечисляет все типы, относящиеся к экземпляру шаблона). В любом случае, хорошая работа по поиску реальной проблемы :-). - person rubenvb; 31.10.2013
comment
Рад, что смог помочь. Порадуйтесь еще за голосование и галочку. ;-) - person Grimm The Opiner; 31.10.2013

В вашем коде Type1 выводится как double (поскольку Eigen::MatrixXd определяется таким образом ).

Затем вы пытаетесь сделать

Type1 tmp = matrix(0, 0);

И я боюсь, что моих знаний об Eigen недостаточно, поэтому я прогнал его через Clang 3.3 и получил эту ошибку:

test.cpp:9:7: error: no viable conversion from 'Scalar' (aka 'double') to
      'Eigen::Matrix<double, -1, -1, 0, -1, -1>'
Type1 tmp = matrix(0, 0);           // getting compiler error here
      ^     ~~~~~~~~~~~~
test.cpp:17:1: note: in instantiation of function template specialization
      'myFunc<Eigen::Matrix<double, -1, -1, 0, -1, -1> >' requested here
myFunc(m);
^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:210:5: note: candidate constructor not viable:
      no known conversion from 'Scalar' (aka 'double') to
      'internal::constructor_without_unaligned_array_assert' for 1st argument
    Matrix(internal::constructor_without_unaligned_array_assert)
    ^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:284:25: note: candidate constructor not
      viable: no known conversion from 'Scalar' (aka 'double') to 'const
      Eigen::Matrix<double, -1, -1, 0, -1, -1> &' for 1st argument
    EIGEN_STRONG_INLINE Matrix(const Matrix& other)
                        ^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:272:25: note: candidate template ignored:
      could not match 'MatrixBase<type-parameter-0-0>' against 'double'
    EIGEN_STRONG_INLINE Matrix(const MatrixBase<OtherDerived>& other)
                        ^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:292:25: note: candidate template ignored:
      could not match 'ReturnByValue<type-parameter-0-0>' against 'double'
    EIGEN_STRONG_INLINE Matrix(const ReturnByValue<OtherDerived>& other)
                        ^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:303:25: note: candidate template ignored:
      could not match 'EigenBase<type-parameter-0-0>' against 'double'
    EIGEN_STRONG_INLINE Matrix(const EigenBase<OtherDerived> &other)
                        ^
1 error generated.

что говорит мне, что вы не можете вызывать matrix таким образом, с двумя 0 в качестве аргументов. Это также странный синтаксис, потому что класс MatrixBase не имеет operator(), который вы, кажется, пытаетесь вызвать.

person rubenvb    schedule 31.10.2013