这种抽象模板矩阵类数据类型的方式好吗?



我最近不得不编写自己的矩阵乘法库。最初,我将其编写为模板类,然后我意识到大多数类使用矩阵类而不关心矩阵类使用的数据类型,因为它们只是执行一定的转换和矩阵而不检查结果。所以他们真的不应该知道数据类型。我正在考虑创建一个带有指向数据的 void 指针的矩阵类。

class Mat
{
private:
void *data;
int dtype; // data type used by matrix
int cols, rows;
template<class type>
Mat add(const Mat& a, type unused); // notice unused parameters
public:
Mat(int dtype);
~Mat();
Mat operator+(const Mat& a);
template<class type>
type* getdata(); // this only function  that exposes the 
//datatype to the user since they want to read the elements
};

我需要一个加法函数作为模板,因为它使用 SSE 内部函数加速计算,并且我使用模板类抽象了内部函数。因此,我想在模板中添加一个未使用的参数,以便编译器能够区分不同的模板。

Mat Mat::operator+(const Mat& a)
{
Mat result;
switch(dtype)
{
case 0: // int
result = this->add<int>(a, 0);
break;
case 1: // float
result = this->add<float>(a, 0);
break;
};
return result;
}

这是一个坏主意吗? 如果不是任何方法可以摆脱 add 方法中未使用的参数?

我的另一个想法是使 IntMatrix,浮点矩阵类继承自 Mat 类,只是为了让它使用模板类型调用 add 函数,以避免在运算符重载中添加大小写开关。这也是一个糟糕的设计吗?

澄清

我希望能够有 2 个向量:

vector<Transform*> transformVector; // list of classes doing operation on matrix
vector<Mat*> results; // intermediate results vector
results.push_back(input_mat)
for(int i = 0; i < transformVector.size(); ++i){
results.push_back(transformVector[i]->transform(results[i]));
// transform here might have to return a result of type float
// even though the input was of type int
}

使Mat类模板化并让编译器创建必要的添加函数会更有效。

使用当前实现时,您必须为每个新类型添加新的开关大小写,并注意将void*正确转换为正确的类型。当您使用模板时,编译器将通过检查您的类型来帮助您。

您甚至可以创建一个模板,允许您将Mat<int>添加到Mat<float>(或另外两个不同类型的矩阵(。

template <typename T, size_t Col, size_t Row>
Mat {
std::array<T, Col * Row> data; // or other data structure
// ...
template <typename OtherT>
add(const Mat<OtherT, Col, Row>& other);
};

这里的一个难点是type * getData()。 同样,要么返回纯void *并要求调用方对其执行显式转换,要么必须使用模板化函数。

长话短说,您已经为一堆模板方法更改了一个模板化类(其中重载在编译时解决(,并且有一些开关用于在运行时解析某些函数。

你说大多数类使用矩阵类而不关心数据类型。这正是模板的目的:一堆独立于底层类型的存储和处理(模板可以做更多的事情,但为此而创建的(

void *始终是一个安全的指针,是 C 兼容 API 的绝佳选择。但是,除非遇到性能问题(模板可以在小系统上使用过多内存,因为它们为每个实现声明了不同的类(*((,并且可以证明void *更适合特定用例,否则您应该坚持通用规则。编写简单易读的代码,仅在发现瓶颈时才进行优化。

编辑后,我可以看到您希望将不同底层类型的矩阵存储在单个容器中。如果所有矩阵都可以从常见的非模板化类型派生,我可以想象多态性,但如果你以后突然陷入type * getData()问题,我不会感到惊讶:你静态转换了一个 void 指针,所以编译器没有办法阻止你做一个糟糕的强制转换。另一种可能性是std::variant矩阵(如果C++17(或boost::variant或任何其他变体或任何替代。其中一些实现了在运行时防止错误转换的技巧。

如果不对真正的问题进行实验,很难知道哪种方式是最好的......


其他一些语言(如Java(没有模板(每个实现都有不同的类(,而是泛型(作用于对象的通用类(。优点只有一个类,因此关于在链接时不可用的正确模板的问题已经消失,缺点是它需要一些技巧才能使实际类型在运行时可用。

相关内容

最新更新