如何围绕表达式模板编写第三方库包装类

时间:2015-03-10 16:09:54

标签: c++ eigen armadillo expression-templates

我们正在尝试在我的研究小组中实施一个新的C ++代码来执行大型数值模拟(有限元,有限差分方法,拓扑优化等)。该软件将被来自学术界和工业界的人们使用。

对于软件的密集线性代数部分,我们想要使用Eigen或Armadillo。我们希望围绕这些包构建一个包装器有两个原因:1。向用户而不是第三方API公开我们自己的API; 2.如果我们将来需要切换库。我理解原因2是一种非常昂贵的保险形式,但我们使用之前的模拟软件遇到了这种情况。

我遇到的有关包装第三方库的信息来自以下来源:

我的问题涉及构建此包装类的最佳方法。理想情况下,薄层包装将是最好的,如:

template< typename T >
class my_vec {
private:
    arma::Col< T > _arma_vec;
};

或其与特征向量的等价物。

然后,我的班级会将第三方库类称为:

my_vec::foo() { return _arma_vec.foo(); }

我认为(我想对此进行确认)这个薄层的问题是我失去了从这些库已经实现的表达模板中获得的速度。例如,在Armadillo中,执行以下操作:

// Assuming these vectors were already populated.
a =  b + c + d;

变成这样:

for ( std::size_t i = 0; i < a.size(); ++i ) {
    a[i] = b[i] + c[i] + d[i];
}

由于expression templates的实施而没有创建任何临时对象。同样的情况也适用于Eigen。

就我而言,我失去表达模板的力量的原因是,虽然Armadillo或Eigen不会创造属于他们自己的临时工,但我的班级my_vec确实如此。避免这种情况的唯一方法是在表达模板周围构建一个薄层包装器。但是,在这一点上,这似乎违反了YAGNI原则。

这个相关问题:

建议使用类似的东西:

my_vec a, b, c;
// ... populate vectors
a._arma_vec = b._arma_vec + c._arma_vec;

是否可以使用这样的东西?

template< typename T >
arma::Col< T > &
my_vec< T >::data() { return _arma_vec; }

a.data() = b.data() + c.data();

或者使用某些运算符重载来隐藏用户的数据()? 如果我们不希望直接使用这些库,还有哪些其他选择?使用宏?如果我们决定使用C ++ 11,请使用别名吗?

或者构建这个包装类最方便的方法是什么?

1 个答案:

答案 0 :(得分:1)

仅供将来参考,我决定实施我的解决方案:我以下列方式重载了运算符+:

template< typename T1, typename T2 >
auto
operator+(
        const my_vec< T1 > & X,
        const my_vec< T2 > & Y ) ->decltype( X.data() + Y.data() )
{
    return X.data() + Y.data();
}

template< typename T1, typename T2 >
auto
operator+(
        const my_vec< T1 > & X,
        const T2 &           Y ) ->decltype( X.data() + Y )
{
    return X.data() + Y;
}

template< typename T1, typename T2 >
auto
operator+(
        const T1 &           X,
        const my_vec< T2 > & Y ) ->decltype( X + Y.data() )
{
    return X + Y.data();
}

然后,我在my_vec类中使用以下内容重载了operator =

template< typename T >
template< typename A >
const my_vec< T > &
my_vec< T >::operator=(
        const A & X )
{
    _arma_vec = X;

    return *this;
}