我正在做一个线性代数模块,以提高我的数学知识,因为我将需要一个轻量级线性代数模块,我的未来工作与Vulkan!
我试图保持一种类似blas的例程风格,例如,相关的函数称为:
template <typename T, std::size_t M, std::size_t N>
Matrix<T, N, M> transposed(const DenseBase<T, M, N>& mat)整个模块是模板,并与编译时大小矩阵工作。我使用std::vector作为存储容器,因为我希望将它分配到堆中(用于大型矩阵)。
第二个目标是通过引用提供对行/列元素的访问,例如:
Matrix<float, 10, 10> matrix{};
matrix.col(1)[1] = 5; // 2nd element of 2nd matrix's column is now set to 5为了实现这一点,我有一个带有基类的层次结构:
template <typename T, std::size_t M, std::size_t N>
class DenseBase
{
public:
using Matrixbase = Matrix<T, M, N>;
using Row = Rowview<DenseBase, T, N>;
using Col = Colview<DenseBase, T, M>;
using ConstRow = const Rowview<const DenseBase, const T, N>;
using ConstCol = const Colview<const DenseBase, const T, M>;
Row row(std::size_t index) { return Row{*this, index}; }
Col col(std::size_t index) { return Col{*this, index}; }
ConstRow row(std::size_t index) const { return ConstRow{*this, index}; }
ConstCol col(std::size_t index) const { return ConstCol{*this, index}; }
T& operator()(std::size_t row, std::size_t col) { return coeff(row, col); }
T& operator[](std::size_t index) { return coeff(index); }
const T& operator()(std::size_t row, std::size_t col) const { return coeff(row, col); }
const T& operator[](std::size_t index) const { return coeff(index); }
virtual T& coeff(std::size_t row, std::size_t col) = 0;
virtual const T& coeff(std::size_t row, std::size_t col) const = 0;
virtual T& coeff(std::size_t index) = 0;
virtual const T& coeff(std::size_t index) const = 0;
};然后,我有一个Rowview,Colview类,它以Densebase作为参数并实现coeff函数:
template <typename Parent, typename T, std::size_t N>
class Rowview : public DenseBase<T, 1, N>
{
public:
Rowview(Parent& parent, std::size_t row) : parent_{parent}, row_{row} {}
T& coeff(std::size_t, std::size_t col) { return parent_(row_, col); }
T& coeff(std::size_t index) { return parent_(row_, index); }
const T& coeff(std::size_t, std::size_t col) const { return parent_(row_, col); }
const T& coeff(std::size_t index) const { return parent_(row_, index); }
private:
Parent& parent_;
std::size_t row_;
};最后,矩阵类本身,用std::vector和实现的coeff方法来访问其元素。
我真的需要一些建议,也许是一些关于如何改进架构的想法。我不喜欢抽象模板类的想法,但我还没有其他选择。
请注意,您可以在GitHub上找到整个代码。
发布于 2015-05-21 10:09:50
由于您使用的是矩阵,所以我认为您不需要virtual提供的运行时多态行为,而是需要创建virtual函数,以便从基类的方法调用派生类的方法。如果是这样的话,您可以使用静态多态性来代替,这要归功于奇怪的是反复出现的模板模式成语。
换句话说,让DenseBase接受一个与派生类的类型相对应的Derived模板参数:
template <typename T, std::size_t M, std::size_t N, typename Derived>
class DenseBase
{
// ...
}然后,使派生类将它们自己的类型提供给此模板参数:
template <typename Parent, typename T, std::size_t N>
class Rowview : public DenseBase<T, 1, N, Rowview<Parent, T, N>>
{
// ...
}现在,在DenseBase中添加几个方法,以便在需要时进行向下转换。由于您通过模板参数Derived在编译时知道派生类型,所以可以使用static_cast进行安全的下播:
Derived& derived() { return static_cast<Derived&>(*this); }
const Derived& derived() const { return static_cast<Derived&>(*this); }现在可以在coeff中重写DenseBase方法,这样它们就不需要再使用virtual来调用派生类中的coeff方法了:
T& coeff(std::size_t row, std::size_t col) { return derived().coeff(row, col); }
const T& coeff(std::size_t row, std::size_t col) const { return derived().coeff(row, col); }
T& coeff(std::size_t index) { return derived().coeff(index); }
const T& coeff(std::size_t index) const { return derived().coeff(index); }这样,您就可以获得多态的一些好处,而不必支付运行时多态性的成本,我认为这样的类不需要这样做。这是有点棘手的理解和使用在一开始,但它有明显的好处。
https://codereview.stackexchange.com/questions/90906
复制相似问题