标量类型的特征模板
Eigen template on scalar type
我正在编写包含大量 classes 的代码,该模板基于标量类型 T
,并在 std::valarray<T>
等容器上实现方法。我想添加对 Eigen 容器的支持,但我很难找到一种方法,仅在标量类型上进行模板化,同时保持 Eigen 的一些灵活性。
例如,Eigen docs 建议使用 Eigen::DenseBase<Derived>
,但这似乎意味着我必须将所有 class 定义更改为数组类型 Derived
然后到处使用 Derived::Scalar
。仅仅支持另一个容器就很麻烦。
我也可以只使用 Matrix<T,Dynamic,Dynamic>
,但这非常有限制。对于我关心的情况,我认为一个合理的中间立场是使用 Ref<Matrix<T,Dynamic,Dynamic>>
,因为这将覆盖 Matrix
及其带有一个接口的切片。但这似乎不起作用,我不确定为什么。这是我的意思的具体示例:
#include<iostream>
#include<Eigen/Dense>
using namespace std;
using namespace Eigen;
double
sum1(const Ref<const Matrix<double,Dynamic,Dynamic>> &m)
{
double x = 0.0;
for (int j=0; j<m.cols(); ++j)
for (int i=0; i<m.rows(); ++i)
x += m(i,j);
return x;
}
template <typename T>
T
sum2(const Ref<const Matrix<T,Dynamic,Dynamic>> &m)
{
T x = 0.0;
for (int j=0; j<m.cols(); ++j)
for (int i=0; i<m.rows(); ++i)
x += m(i,j);
return x;
}
int main()
{
Matrix<double,Dynamic,Dynamic> a(2,2);
a << 0,2,1,3;
cout << "sum1(a) = " << sum1(a) << endl; // ok
cout << "sum2(a) = " << sum2(a) << endl; // error
cout << "sum2(a) = " << sum2<double>(a) << endl; // ok
return 0;
}
但是编译的时候出现错误:
$ clang++ -std=c++17 -I/usr/include/eigen3 eig2.cpp -o eig2
eig2.cpp:33:29: error: no matching function for call to 'sum2'
cout << "sum2(a) = " << sum2(a) << endl; // error
^~~~
eig2.cpp:19:1: note: candidate template ignored: could not match 'Ref' against
'Matrix'
sum2(const Ref<const Matrix<T,Dynamic,Dynamic>> &m)
^
1 error generated.
有没有办法实现 sum2
以使其支持 Matrix
和 Ref
并且不需要显式模板参数来使用它?
的原因
template <typename T>
T
sum2(const Ref<const Matrix<T,Dynamic,Dynamic>> &m)
对 Matrix<T,Dynamic,Dynamic>
不起作用是因为 C++ 不能同时推导模板参数和进行类型转换(Ref
与 Matrix
是不同的类型,但是它可以用 O(1) 的努力来构建。
允许您保留函数体的一个替代方案(需要 C++11 或更高版本)是:
template<typename Derived, typename T=typename Derived::Scalar>
T sum3(const MatrixBase<Derived> &m)
如果你想也允许 Array
,你可以使用 DenseBase
,如果你想允许稀疏矩阵,你可以使用 EigenBase
.
但是,这不等同于具有显式类型替换的 Ref
实现,因为如果 Derived
是一个表达式,它可能会在您的函数中被计算多次。
另一种方法是写
template <typename T>
T
sum_impl(const Ref<const Matrix<T,Dynamic,Dynamic>> &m)
{ /* here comes the actual implementation */ }
template<typename Derived>
typename Derived::Scalar sum4(const Eigen::MatrixBase<Derived>& m)
{
return sum_impl<typename Derived::Scalar>(m);
}
我正在编写包含大量 classes 的代码,该模板基于标量类型 T
,并在 std::valarray<T>
等容器上实现方法。我想添加对 Eigen 容器的支持,但我很难找到一种方法,仅在标量类型上进行模板化,同时保持 Eigen 的一些灵活性。
例如,Eigen docs 建议使用 Eigen::DenseBase<Derived>
,但这似乎意味着我必须将所有 class 定义更改为数组类型 Derived
然后到处使用 Derived::Scalar
。仅仅支持另一个容器就很麻烦。
我也可以只使用 Matrix<T,Dynamic,Dynamic>
,但这非常有限制。对于我关心的情况,我认为一个合理的中间立场是使用 Ref<Matrix<T,Dynamic,Dynamic>>
,因为这将覆盖 Matrix
及其带有一个接口的切片。但这似乎不起作用,我不确定为什么。这是我的意思的具体示例:
#include<iostream>
#include<Eigen/Dense>
using namespace std;
using namespace Eigen;
double
sum1(const Ref<const Matrix<double,Dynamic,Dynamic>> &m)
{
double x = 0.0;
for (int j=0; j<m.cols(); ++j)
for (int i=0; i<m.rows(); ++i)
x += m(i,j);
return x;
}
template <typename T>
T
sum2(const Ref<const Matrix<T,Dynamic,Dynamic>> &m)
{
T x = 0.0;
for (int j=0; j<m.cols(); ++j)
for (int i=0; i<m.rows(); ++i)
x += m(i,j);
return x;
}
int main()
{
Matrix<double,Dynamic,Dynamic> a(2,2);
a << 0,2,1,3;
cout << "sum1(a) = " << sum1(a) << endl; // ok
cout << "sum2(a) = " << sum2(a) << endl; // error
cout << "sum2(a) = " << sum2<double>(a) << endl; // ok
return 0;
}
但是编译的时候出现错误:
$ clang++ -std=c++17 -I/usr/include/eigen3 eig2.cpp -o eig2
eig2.cpp:33:29: error: no matching function for call to 'sum2'
cout << "sum2(a) = " << sum2(a) << endl; // error
^~~~
eig2.cpp:19:1: note: candidate template ignored: could not match 'Ref' against
'Matrix'
sum2(const Ref<const Matrix<T,Dynamic,Dynamic>> &m)
^
1 error generated.
有没有办法实现 sum2
以使其支持 Matrix
和 Ref
并且不需要显式模板参数来使用它?
template <typename T>
T
sum2(const Ref<const Matrix<T,Dynamic,Dynamic>> &m)
对 Matrix<T,Dynamic,Dynamic>
不起作用是因为 C++ 不能同时推导模板参数和进行类型转换(Ref
与 Matrix
是不同的类型,但是它可以用 O(1) 的努力来构建。
允许您保留函数体的一个替代方案(需要 C++11 或更高版本)是:
template<typename Derived, typename T=typename Derived::Scalar>
T sum3(const MatrixBase<Derived> &m)
如果你想也允许 Array
,你可以使用 DenseBase
,如果你想允许稀疏矩阵,你可以使用 EigenBase
.
但是,这不等同于具有显式类型替换的 Ref
实现,因为如果 Derived
是一个表达式,它可能会在您的函数中被计算多次。
另一种方法是写
template <typename T>
T
sum_impl(const Ref<const Matrix<T,Dynamic,Dynamic>> &m)
{ /* here comes the actual implementation */ }
template<typename Derived>
typename Derived::Scalar sum4(const Eigen::MatrixBase<Derived>& m)
{
return sum_impl<typename Derived::Scalar>(m);
}