C ++有效实现包装类

时间:2017-11-05 12:07:29

标签: performance c++11 inline wrapper crtp

我有一个项目广泛使用(高频率)一组有限的关键线性代数运算,如矩阵乘法,矩阵求逆,加法等。这些操作是由少数线性代数库实现的,我会喜欢基准测试而不必重新编译业务逻辑代码以适应这些不同库的不同习惯。

我有兴趣弄清楚在所有这些库中使用包装类作为抽象的最聪明的方法是什么,以便针对我的其余代码标准化这些操作。我目前的方法依赖于奇怪的重复模板模式以及C ++ 11 gcc足够智能以在适当的环境下内联虚拟功能。

这是业务逻辑可用的包装器接口:

template <class T>
class ITensor {

    virtual void initZeros(uint32_t dim1, uint32_t dim2) = 0;
    virtual void initOnes(uint32_t dim1, uint32_t dim2) = 0;
    virtual void initRand(uint32_t dim1, uint32_t dim2) = 0;

    virtual T mult(T& t) = 0;
    virtual T add(T& t) = 0;
};

以下是使用例如的接口的实现。犰狳

template <typename precision> 
class Tensor : public ITensor<Tensor<precision> >
{
  public:

    Tensor(){}
    Tensor(arma::Mat<precision> mat) : M(mat) { }
    ~Tensor(){}

    inline void initOnes(uint32_t dim1, uint32_t dim2) override final
        {  M = arma::ones<arma::Mat<precision> >(dim1,dim2); }
    inline void initZeros(uint32_t dim1, uint32_t dim2) override final
        { M = arma::zeros<arma::Mat<precision> >(dim1,dim2);}
    inline void initRand(uint32_t dim1, uint32_t dim2) override final 
        { M = arma::randu<arma::Mat<precision> >(dim1,dim2);}

    inline Tensor<precision> mult(Tensor<precision>& t1) override final
    {
        Tensor<precision> t(M * t1.M);
        return t;
    }

    inline Tensor<precision> add(Tensor<precision>& t1) override final
    {
        Tensor<precision> t( M + t1.M);
        return t;
    }

    arma::Mat<precision> M;
};

问题:

  1. 在这种情况下使用CRTP和内联是否有意义?
  2. 在优化性能方面可以改进吗?
  3. 正如答案所指出的,由于基类的模板化,这里多态的使用有点奇怪。这就是为什么我认为这仍然有意义:

    你会注意到基类被命名为&#34; Tensor&#34;而不是更具体的东西,比如&#34; ArmadilloTensor&#34; (毕竟,基类使用Armadillo方法实现ITensor方法)。我保持这个名称是因为根据我目前的设计,多态性的使用更多是由于形式主义而不是其他任何东西。计划是让项目代码知道一个名为Tensor的类,它提供了ITensor中指定的功能。对于我想要进行基准测试的每个新库,我只想写一个新的&#34; Tensor&#34;在新编译单元中的类,将编译结果打包到.a存档中,并在进行基准测试时,将业务逻辑代码链接到该库。然后,在不同的实现之间切换成为选择要链接的Tensor实现的问题。无论Tensor方法是由Armadillo还是其他方法实现的,基本代码都是一样的。优点:避免使用知道每个库的代码(它们都是独立的),并且在基本代码中不需要编译时间更改以便使用新的实现。那么,为什么多态?在我看来,我只是想以某种方式形式化需要由添加到基准测试的任何新库实现的功能。实际上,基本代码将在函数参数中与ITensors一起使用,但随后可能会将它们静态广播到方法体本身的Tensors。

1 个答案:

答案 0 :(得分:1)

我可能在这里遗漏了一些东西,或者你没有展示足够的细节。

您使用多态性。正如其名称中所定义的那样,它采用不同的形状(不同的行为)。因此,您有一个用户代码接受的接口,您可以提供该接口的不同实现。

但在您的情况下,您没有单一界面的不同实现。您的ITensor模板会生成不同的类,而Tensor的每个最终实现都来自不同的基础。

考虑您的用户代码是这样的:

template<typename T>
void useTensor(ITensor<T>& tensor);

您可以提供Tensor实施。它与

几乎相同
template<typename T>
void useTensor(T& tensor);

没有CRTP和虚拟电话。现在每个包装器应该实现一些功能集。存在一个问题,即没有明确定义这组功能。编译器在这里提供了很大的帮助,但它并不理想。这就是为什么我们都期待在下一个标准中获得Concepts