【问题标题】:Function templates in C++ with Armadillo带有犰狳的 C++ 中的函数模板
【发布时间】:2015-10-02 00:02:26
【问题描述】:

我正在使用犰狳线性代数库编写一些函数模板,但遇到了一些错误。我仍在学习 C++ 及其方面,因此非常感谢任何可能的解决方案。我的大部分功能如下,

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...
    // ....
}

有什么解决办法吗??

【问题讨论】:

  • 似乎operator *(double, Mat&lt;double&gt;) 返回一个惰性评估,而不是直接返回一个Mat&lt;double&gt;...
  • 错误很明显。模板可以是intint 有成员 n_rows() 吗?
  • @manetsus 编号int 没有n_rows,但Mat&lt;T1&gt; 有。在第二种情况下,由于我只传递Mat 类(或int*Mat&lt;&gt; ...),我认为只有该版本的函数将被实例化。 @Jarod42 是的,这可能是问题所在。
  • 这意味着您想告诉您的第一个(问题中的五个)代码块出现错误,对吧?
  • @Jarod42 - 实际上该库确实提供了一种处理该问题的正确方法:.eval() 成员函数。例如:my_function( (a*A).eval() )

标签: c++ function templates armadillo


【解决方案1】:

使用.eval() 成员函数将犰狳表达式强制转换为矩阵。

然后您可以使用.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;

【讨论】:

  • 哎呀。 ( ) 只是一个愚蠢的错字。感谢您的回答。
【解决方案2】:

我认为有了这些助手:

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...
    // ....
}

【讨论】:

  • 对了,在第二种情况下使用初始化列表有什么意义吗?很高兴学习.. @Jarod42
  • 我更喜欢写{X}而不是冗长的Mat&lt;typename T1::elem_type&gt;(X)或过于含蓄的X
【解决方案3】:

Jarod42的帖子之后,我花了一些时间在这件事上,并找到了另一种可能的解决方案,与Jarod42的非常相似。我正在回复它作为任何可能像我一样陷入同样问题的人的答案。 我刚刚更改了 Jarod42 已经编写的第二个 as_Mat 函数。

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, complex,double...) 等等等等等等。

虽然我不确定代码的性能,而且正如 mtall 提到的 .eval() 函数,此修复对于使用 Armadillo 构建模板库非常有帮助,其中库用户不需要每隔一段时间输入.eval()。再次感谢大家的热心帮助和关注。

【讨论】:

    猜你喜欢
    • 2014-10-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多