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

Her*_*eva 6 c++ expression-templates armadillo eigen

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

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

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

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

template< typename T >
class my_vec {
private:
    arma::Col< T > _arma_vec;
};
Run Code Online (Sandbox Code Playgroud)

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

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

my_vec::foo() { return _arma_vec.foo(); }
Run Code Online (Sandbox Code Playgroud)

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

// Assuming these vectors were already populated.
a =  b + c + d;
Run Code Online (Sandbox Code Playgroud)

变得像这样:

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

由于实现了表达式模板而没有创建任何临时值.同样的情况适用于Eigen.

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

这个相关的问题:

建议使用类似的东西:

my_vec a, b, c;
// ... populate vectors
a._arma_vec = b._arma_vec + c._arma_vec;
Run Code Online (Sandbox Code Playgroud)

可以使用这样的东西吗?

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

a.data() = b.data() + c.data();
Run Code Online (Sandbox Code Playgroud)

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

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

Her*_*eva 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();
}
Run Code Online (Sandbox Code Playgroud)

然后,我使用以下内容在 my_vec 类中重载了运算符=:

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

    return *this;
}
Run Code Online (Sandbox Code Playgroud)