3

我正在编写一个模板矩阵类,我对 * 运算符的重载如何工作感到有些困惑。

我想重载这样的东西(省略不相关的代码):

template<typename T>class Matrix4t
{

friend vector3 operator*(const vector3 &inputV3, const matrix4t &inputM4t);

template <typename scalarT>
friend scalarT operator*(const scalarT &inputSclT, const matrix4t &inputM4t);

public:
const matrix4t operator*(const matrix4t)

vector3 operator*(const vector3 &inputV3);

template <typename scalarT>
const matrix4t operator*(const scalarT&);

}

假设单个乘法的定义正确,我假设这应该允许我的矩阵对象与来自操作数两侧的 vector3 类型的对象相乘,每次都返回一个 vector3。它还应该允许将我的矩阵与标量模板值相乘,可以是浮点数、双精度等。这些方法的定义需要不同,以允许向量与标量乘法,因此不仅仅是对两者都使用模板

但是,在将这个运算符与 vector3 一起使用时,编译器会知道使用显式声明的 vector3 方法,还是会尝试创建该方法的模板化版本,因为定义被写入仅允许标量值,所以这不起作用,然后可能还会抱怨方法重新定义。

关于这是否可行,或者我还能怎么做的任何想法?

干杯

4

1 回答 1

4

我有一种感觉,你的目标可能是一个比需要的更复杂的解决方案,所以我将从头开始构建,并留下一些细节供以后使用。首先,我将开始分析您提出的语法及其含义。

friend vector3 operator*(const vector3 &v, const matrix4t &m);
template <typename scalarT>
friend scalarT operator*(const scalarT &inputSclT, const matrix4t &inputM4t);

这些是朋友声明。Friend 声明声明(告诉编译器存在)类外部的实体,并且应该授予这样的实体对此类(在本例中是模板)内部的完全访问权限。第二个朋友声明是一个自由函数模板operator*,它通过 const 引用获取一个scalarT类型和一个matrix4T<T>对象,并产生一个scalarT值。这个朋友声明似乎很奇怪,因为矩阵乘以标量值通常会产生另一个相同维度的矩阵,而不仅仅是一个标量值。

请注意,在类模板内部,模板的名称matrix4t不是指模板,而是特定的特化(即它代表matrix4t<T>,而不是模板的名称)。这种区别现在可能看起来并不重要,但迟早你会意识到它的重要性。

第二个声明是一个非模板化的自由函数operator*,它通过 const 引用接受 avector3和 amatrix4t并产生另一个vector3。由于我们在 的定义中matrix4t,因此模板的名称指的是 specialization matrix4t<T>,但vector3仅指的是template,而不是任何特定的实例化。您应该将其设为接受vector3<U>任何给定类型的模板,或者将其设为接受单一类型(可以是我们模板U的参数)的非模板函数:与其他声明一样,返回值可能关闭或不关闭...取决于向量的维度(是行还是列?)Tvector3<T>

关于实际交友,我建议您阅读此答案以回答不同的类似问题。

对于实际的运算符,对于标量类型,我建议采用以下方法:

  • 实现operator*=将与存储的类型相同的标量作为参数
  • operator*实现两个版本operator*=

.

template <typename T> class matrix4t {
public:
    matrix4t& operator*=( T scalar ); // and implement
    friend matrix4t operator*( matrix4t lhs, T scalar ) {
       return lhs*=scalar;
    }
    friend matrix4t operator*( T scalar, matrix4t rhs ) {
       return rhs*=scalar;
    }
};

注意:operator*=实现一次,将矩阵作为左侧(您也可以提供将矩阵作为右侧的重载,但它看起来有点奇怪:5 *= matrix产生一个矩阵......)。实现operator*为自由函数(友谊仅用于为每个实例化类型提供自由函数,阅读链接答案),通过转发到operator*=.

对于乘以向量的情况(并且因为它不是对称的),分派到单个实现的技巧将不起作用,但是您可以像上面那样将这两个实现作为非模板化的朋友提供。

如果您想提供混合类型的操作,那么以上所有内容都必须是模板。增加的复杂性不是模板,而是如果要提升类型,则确定结果类型应该是什么。使用 C++11,最简单的方法是使用decltype和尾随返回类型:

template <typename U>
friend auto operator*( matrixt4 lhs, U scalar ) -> matrix4t< decltype(scalar * element(0,0) ) > {
   // implement here
}

同样对于operator*(scalar,matrix). 请注意,如果您正在提升类型,operator*=可能根本没有意义(因为类型与 lhs 相同),或者如果这样做,它可能会或可能不会产生您想要的结果。如果您考虑这样做,则operator+必须matrix4t<A>通过引用获取参数(因为它可能不是适当的类型)并复制到matrix4t<B>返回类型(其中AB分别是被相乘的矩阵的类型和结果)。

从这里开始,您应该决定您需要或想要实施什么,并且您可能想在遇到更具体的问题时提出这些问题。

于 2012-08-08T03:39:04.447 回答