我有一种感觉,你的目标可能是一个比需要的更复杂的解决方案,所以我将从头开始构建,并留下一些细节供以后使用。首先,我将开始分析您提出的语法及其含义。
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
的参数)的非模板函数:与其他声明一样,返回值可能关闭或不关闭...取决于向量的维度(是行还是列?)T
vector3<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>
返回类型(其中A
和B
分别是被相乘的矩阵的类型和结果)。
从这里开始,您应该决定您需要或想要实施什么,并且您可能想在遇到更具体的问题时提出这些问题。