C ++模板运算符重载 [英] C++ Template operator overload

查看:56
本文介绍了C ++模板运算符重载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写模板矩阵类,并且对*运算符的重载方式有点困惑.

我想重载这样的内容(省略无关的代码):

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.同样,它应该允许矩阵与标量模板值相乘,标量模板值可以是float,double等.这些方法的定义必须有所不同,以允许向量与标量相乘,因此不仅要对这两个都使用模板, /p>

在将此操作符与vector3一起使用时,编译器会知道使用显式声明的vector3方法,还是会尝试创建该方法的模板化版本,由于定义只允许标量值,然后可能还会抱怨方法的重新定义.

是否有任何想法,或者我还能怎么做?

欢呼

解决方案

我感觉到您可能会寻求比所需的更复杂的解决方案,因此我将从头开始构建,并留一些细节供以后使用.首先,我将开始分析您建议的语法及其含义.

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

这些是朋友声明.朋友声明 declare (告诉编译器是否存在)在该类外部的实体,并且应授予该实体对此类内部的完全访问权限(在这种情况下为模板).第二个朋友声明是自由函数模板operator*,该模板通过const引用均采用scalarT类型和matrix4T<T>对象,并产生scalarT值.这个朋友声明似乎很奇怪,因为矩阵与标量值的乘积通常会产生另一个具有相同维数的矩阵,而不仅仅是标量值.

请注意,在类模板中,模板matrix4t的名称不是引用模板,而是特定的专业化名称(即,它表示matrix4t<T>,而不是模板的名称).这种区别现在似乎并不重要,但是迟早您将意识到它的重要性.

第二个声明是一个非模板的自由函数operator*,该函数通过const引用同时获取vector3matrix4t,并生成另一个vector3.由于我们位于matrix4t的定义之内,因此模板的名称指的是专业化matrix4t<T>,但是vector3仅指的是 template ,而不是任何特定的实例化.您应该使模板接受任何给定类型Uvector3<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>返回类型(其中AB分别是要相乘的矩阵的类型和结果).

从现在开始,您应该确定需要或想要实现的内容,并且可能想问一些更具体的问题.

I'm writing a template matrix class, and I am a bit confused as to how overloading the * operator would work.

I would want to overload something like this (omitting irrelevant code):

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&);

}

Assuming correct definitions for the individual multiplications I assume this should allow multiplication of my matrix object with an object of type vector3 from both sides of the operand, returning a vector3 each time. Also it should allow multiplication of my matrix with a scalar template value, which could be float, double etc. The definitions of these methods would need to be different, to allow for vector vs scalar multiplication, hence not just using the template for both

On using this operator with a vector3 though, would the compiler know to use the explicitly declared vector3 method, or would it try and create the templated version of the method, which would not work as the definition is written to only allow for a scalar value, and probably also then complain about method redefinition.

Any thoughts on if this would work, or how else I could go about it?

Cheers

解决方案

I have the feeling that you might be aiming for a more complex solution than needed, so I will start building from the ground up, and leave some details for later. First I will start analyzing your proposed syntax and what it means.

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

These are friend declarations. Friend declarations declare (tell the compiler that there is) an entity external to the class and that such an entity should be granted full access to the internals of this class (which in this case is a template). The second friend declaration is of a free function template operator* that takes a scalarT type and a matrix4T<T> object both by const reference and yields an scalarT value. This friend declaration seems strange in that the multiplication of a matrix by a scalar value usually yields another matrix of the same dimensions, rather than just a scalar value.

Note that inside the class template, the name of the template matrix4t does not refer to the template, but the particular specialization (i.e. it represents matrix4t<T>, not the name of the template). The distinction might not seem important now, but sooner or later you will realize the importance of it.

The second declaration is of a non-templated free function operator* that takes a vector3 and a matrix4t both by const reference and yields another vector3. Since we are inside the definition of the matrix4t, the name of the template refers to the specialization matrix4t<T>, but vector3 refers just to the template, and not any particular instantiation. You should either make that a template that accepts vector3<U> for any given type U, or else a non-templated function that accepts a single type (which can be the T argument of our template): vector3<T>. In the same way as with the other declaration, the return value might be off or not... depends on what are the dimensions of the vector (is it row or column?)

Regarding the actual befriending, I recommend that you read this answer to a different similar question.

As of the actual operators, for the scalar type, I would suggest the following approach:

  • Implement operator*= taking the scalar of the same type as is stored as an argument
  • Implement both versions of operator* in terms of 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;
    }
};

Notes: operator*= is implemented once, taking the matrix as left hand side (you could also offer an overload taking the matrix as right hand side, but it would look a bit strange: 5 *= matrix yielding a matrix...). Implement operator* as free functions (friendship is only used to provide the free function for each instantiating type, read the linked answer), by forwarding to operator*=.

For the case of multiplying by a vector (and because it is not symmetric) the trick of dispatching to a single implementation will not work, but you can provide the two implementations as non-templated friends as above.

If you wanted to provide operations with mixed types, then all of the above would have to be templates. The added complexity is not the template, but rather determining what the result types should be if you want to promote the types. With C++11 the easiest way would be using decltype and trailing return types:

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

And similarly for operator*(scalar,matrix). Note that if you are promoting types, operator*= might not make sense at all (as the type would be the same as the lhs), or if it did, it might or might not produce the result that you want. If you consider doing it, the operator+ would have to take the matrix4t<A> argument by reference (as it might not be of the appropriate type) and copy into the matrix4t<B> return type (where A and B are respectively the types of the matrix being multiplied and the result).

From here on, you should decide what you need or want to implement, and you might want to ask more specific questions as they come by.

这篇关于C ++模板运算符重载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆