C++ C+中的重载运算符+;使用模板类
我有以下模板类:C++ C+中的重载运算符+;使用模板类,c++,class,templates,overloading,operator-keyword,C++,Class,Templates,Overloading,Operator Keyword,我有以下模板类: template <class T> class Matrix { public: Matrix(size_t rows, size_t columns, const T elements = 0); // scalar multiplication Matrix<T> operator*(const T& rhs){ Matrix<T>
template <class T>
class Matrix {
public:
Matrix(size_t rows, size_t columns, const T elements = 0);
// scalar multiplication
Matrix<T> operator*(const T& rhs){
Matrix<T> result(rows, columns);
for(size_t index = 0; index < rows * columns; ++index){
result.elements[index] = elements[index] * rhs;
}
return result;
}
Matrix <T> operator*(const T& lhs, const Matrix<T>& rhs);
const size_t rows;
const size_t columns;
private:
std::vector<T> elements;
};
模板
类矩阵{
公众:
矩阵(大小行、大小列、常量元素=0);
//标量乘法
矩阵运算符*(常数T和rhs){
矩阵结果(行、列);
对于(大小索引=0;索引<行*列;++索引){
结果.元素[索引]=元素[索引]*rhs;
}
返回结果;
}
矩阵运算符*(常数T和lhs、常数矩阵和rhs);
常量大小\u t行;
常量大小\u t列;
私人:
std::向量元素;
};
以及运算符的以下实现*:
// scalar multiplication
template <class T>
Matrix<T> Matrix<T>::operator*(const T& lhs, const Matrix<T>& rhs){
Matrix<T> result(rhs.rows, rhs.columns);
for(size_t index = 0; index < rhs.rows * rhs.columns; ++index){
result.elements[index] = elements[index] * lhs;
}
return result;
}
//标量乘法
模板
矩阵::运算符*(常数T和lhs、常数矩阵和rhs){
矩阵结果(rhs.行、rhs.列);
对于(大小索引=0;索引
当我试图编译时,clang说:错误:重载的“operator*”必须是一元或二元运算符(有3个参数)|
我不太明白,我在这件事上遗漏了什么。一般来说,模板类在重载操作符时给我带来了困难,我不知道为什么。关于这个主题,这里有一些帖子,我尝试了一些代码的变体,但没有一个有效。您正在声明
矩阵运算符*(const T&lhs,const Matrix&rhs)
作为成员函数,它有一个隐式参数this
,这就是为什么编译器抱怨它“有3个参数”
你可以让它成为一个免费的模板函数
template <class T>
class Matrix {
...
template <class Z>
friend Matrix<Z> operator*(const Z& lhs, const Matrix<Z>& rhs);
...
};
模板
类矩阵{
...
模板
友元矩阵算子*(常数Z和lhs,常数矩阵和rhs);
...
};
及
//标量乘法
模板
矩阵运算符*(常数Z和lhs,常数矩阵和rhs){
矩阵结果(rhs.行、rhs.列);
对于(大小索引=0;索引
您的函数是成员函数。成员函数有一个隐藏参数,即this指针
您要么需要使运算符*成为非成员函数,要么需要去掉运算符*函数的一个参数(然后将“this”中的数据与传入矩阵中的数据相乘)解决此问题的简单且合理有效的方法如下:
矩阵和运算符*=(SomeType const&)
和类似的操作。这些是改变类实例的变异操作,然后返回对*this
的引用*=
实现其他内联友元操作,其中lhs(通常)参数按值获取、修改并返回operator*
开始而不是从operator*=
开始更有效
因此,您将有:
template<class T, etc>
struct Matrix{
Matrix& operator*=(T const&);
Matrix& operator*=(Matrix const&);
Matrix& operator+=(Matrix const&);
现在您只需要实现一些传统的方法
这些friend
运算符是为矩阵的每个模板实例自动生成的非模板内联非方法函数
直接的问题是,非静态运算符除了两个显式参数外,实际上还接受了一个隐式this
,而二进制运算符不能接受3个参数
复杂且更有效的解决方案涉及一种通常称为“表达式模板”的技术。缺点是表达式模板编写起来比较复杂,并且在
auto
关键字和类似情况下存在一些弱点
例如:
Matrix m = m1 * m2 + m3 * m4 + m5 + m6;
表达式模板只需对矩阵的内部数据进行一次分配即可完成上述操作
我的上述代码将复制m1
,将结果乘以m2
。然后它将复制m3
,然后将其乘以m4
。然后,它将把所有内容加起来,而不制作任何额外的副本。最后,此结果将移动到m
因此,将创建两个矩阵,而不是表达式模板中的1
一个更简单的解决方案(如OP的设计)将创建5个矩阵,而不是2个。作为成员函数,它将
这个隐式地作为第一个参数,但您希望再添加2个。假设你有矩阵a,b,c代码>你的操作符会被称为a.operator*(b,c)
这有意义吗?否;)相关报道:我之前试过friend,但也没用@songyuanyao@kimsay我的错。修正。谢谢@songyuanyao。我是否只需要朋友来访问私人领域,或者还有更多吗?@kimsay仅用于访问私人领域,仅此而已。谢谢!很多时候,我不确定我应该在类定义内部还是外部实现一个函数。有一般规则吗?@kimsay如果它很短,并且您对inline
及其危险没有意见,请在类定义中这样做。如果不是,把它放在别处?对于上述Koenig friend运算符,您必须在类定义中执行此操作(因为无法在类外引用运算符):这也意味着(对我来说)它们应该总是短的。而且friend仅用于访问私有字段?@kimsay nope:它可以做很多事情。它使ADL工作顺利,使操作符本身成为非模板(有一些很好的特性:模板操作符可能很脆弱),使它们成为非成员二进制操作符,等等。抱歉,明白了!谢谢!@牦牛
friend Matrix operator*(T const& t, Matrix m){ m*=t; return m; }
friend Matrix operator*(Matrix m, T const& t){ m*=t; return m; }
friend Matrix operator*(Matrix lhs, Matrix const& rhs){ lhs*=rhs; return lhs; }
friend Matrix operator+(Matrix lhs, Matrix const& rhs){ lhs+=rhs; return lhs; }
Matrix m = m1 * m2 + m3 * m4 + m5 + m6;