2015-10-02 2 views
2

Я пишу некоторые шаблоны функций, используя библиотеку линейной алгебры Armadillo, но он сталкивается с некоторыми ошибками. Я все еще изучаю C++ и его аспекты, поэтому буду очень благодарен за любые возможные решения. Большинство моих функций как следующий,Шаблоны функций в C++ с Armadillo

template<typename T1> 
void some_function(const Mat<T1> & p) 
{ 
    unsigned int n = p.n_rows; 
    // do some stuffs... 
    // .... 
} 

Моя основная функция содержит:

Mat<double> A = ones<Mat<double>>(4,4); 
int a(2); 
some_function(A); // runs perfectly 
some_function(a*A); // compilation error as follows 

test_function.hpp:35:8: note: template argument deduction/substitution failed: 
test.cpp:22:17: note: ‘arma::enable_if2<true, const arma::eOp<arma::Mat<double>, arma::eop_scalar_times> >::result {aka const arma::eOp<arma::Mat<double>, arma::eop_scalar_times>}’ is not derived from ‘const arma::Mat<eT>’ 
some_function(a*A); 

Если изменить функцию следующим образом:

template<typename T1> 
void some_function(const T1 & p) 
{ 
    unsigned int n = p.n_rows; 
    // do some stuffs... 
    // .... 
} 

Затем он дает ошибку компиляции, как следует:

test_function.hpp: In instantiation of ‘bool some_function(const T1&) [with T1 = arma::eOp<arma::Mat<double>, arma::eop_scalar_times>]’: 
test.cpp:22:17: required from here 
test_function.hpp:37:26: error: ‘const class arma::eOp<arma::Mat<double>, arma::eop_scalar_times>’ has no member named ‘n_rows’ 
unsigned int n = p.n_rows; 

Но функции без шаблонов работают отлично, например

void some_function(const Mat<double> & p) 
{ 
    unsigned int n = p.n_rows(); 
    // do some stuffs... 
    // .... 
} 

Любые решения?

+0

Кажется, что 'operator * (double, Mat )' возвращает ленивую оценку, а не непосредственно 'Mat ' ... – Jarod42

+0

Ошибка настолько ясна. Шаблон может быть 'int'. У 'int' есть член' n_rows() '? – manetsus

+0

@manetsus № 'int' не имеет' n_rows', но 'Mat ' имеет. Во втором случае, поскольку я только передаю класс 'Mat' (или' int * Mat <> '...), я думаю, будет создана только эта версия функции. @ Jarod42 Да, это может быть проблема. –

ответ

1

Я думаю, что с этими помощниками:

template <typename T> 
const Mat<T>& as_Mat(const Mat<T>& m) {return m;} 

template<typename T1, typename eop_type> 
Mat<typename T1::elem_type> as_Mat(const eOp<T1, eop_type>& X) 
{ 
    return {X}; 
} 

Вы можете написать:

template<typename T> 
void some_function(const T & p) 
{ 
    const auto& mat = as_mat(p); 
    unsigned int n = mat.n_rows(); 
    // do some stuffs... 
    // .... 
} 
+0

Кстати, есть ли смысл использовать список инициализаторов во втором случае? С удовольствием узнаем .. @ Jarod42 –

+0

Я предпочитаю писать '{X}' над verbose 'Mat (X)' или слишком неявный 'X'. – Jarod42

3

Используйте функцию .eval() члена для принудительного преобразования выражения Armadillo в матрицу.

В качестве входа функции вы можете использовать результат .eval(). Например:

mat A(10,20,fill::randu); 
mat B(10,20,fill::randu); 

some_function((A+B).eval()); 

Также обратите внимание, что класс Mat не имеет функции-члена, называемой n_rows(). Вместо этого он имеет переменную только для чтения, называемую n_rows. Например:

unsigned int n = X.n_rows; 
+0

Ooops. '()' был просто глупой опечаткой. Спасибо за ответ. –

1

После Jarod42 «s пост, я положил некоторое время по этому вопросу и обнаружил еще один из возможных решений этой проблемы, очень похожих на Jarod42» s один. Я отвечаю им как ответ для всех, кто мог бы застрять в этой же проблеме, как я. Я только что изменил вторую функцию as_Mat, которая Jarod42 уже написана.

template <typename T> 
const Mat<T>& as_Mat(const Mat<T>& m) {return m;} 


template<typename T> 
Mat<typename T::elem_type> as_Mat(const T& X) 
{ 
    return {X}; 
} 

И все пользовательские функции будут содержать одну строку, как и раньше.

template<typename T> 
void some_function(const T & X) 
{ 
    const auto& Y = as_Mat(X); 
    // do some stuffs with Y... 
    // .... 
} 

Таким образом, любая отложенная оценка будет преобразована в матрицу, например. A+B, A*B, i*A (i = INT, комплекс <>, двойной ...) и т.д. и т.п. и т.д.

Хотя я не уверен, о выполнении кода, а также, как и mtall упоминается о .eval() функция, это исправление может быть очень полезно для создания шаблонных библиотек с использованием Armadillo, где пользователям библиотеки не нужно ставить .eval() каждый раз. Еще раз спасибо вам за вашу любезную помощь и внимание.