我写了一些代码来管理类模板,类继承和操作符重载,我不知道如何解决有关操作符使用的问题。我有一个包含大量代码的基类(尤其是运算符重载实现和数据持有者):
template <typename _type>
class baseMatrix {
public:
baseMatrix();
~baseMatrix();
//operators
baseMatrix<_type>& operator= (baseMatrix<_type> _mat);
template <typename _input_type> baseMatrix<_type>& operator*= (_input_type _val);
template <typename _input_type> baseMatrix<_type>& operator/= (_input_type _val);
template <typename _input_type> baseMatrix<_type>& operator+= (_input_type _val);
template <typename _input_type> baseMatrix<_type>& operator-= (_input_type _val);
template <typename _input_type> baseMatrix<_type>& operator*= (const baseMatrix<_input_type>& _mat);
template <typename _input_type> baseMatrix<_type>& operator/= (const baseMatrix<_input_type>& _mat);
template <typename _input_type> baseMatrix<_type>& operator+= (const baseMatrix<_input_type>& _mat);
template <typename _input_type> baseMatrix<_type>& operator-= (const baseMatrix<_input_type>& _mat);
protected:
std::vector<_type> data;
};
/* ... */
template <typename _type>
template <typename _input_type>
baseMatrix<_type>& baseMatrix<_type>::operator*=(_input_type _val) {
for (int i = 0; i < data.size(); ++i) data[i]*=_val;
return *this;
};
template <typename _type>
template <typename _input_type>
baseMatrix<_type>& baseMatrix<_type>::operator*=(const baseMatrix<_input_type>& _mat) {
for (int i = 0; i < data.size(); ++i) data[i]*=_mat.data[i];
return *this;
};
/* remaining operator overload functions */
我重载了标量和类参数的运算符。然后,我还有一个额外的类matrix2D
,它从baseMatrix
继承了这些运算符:
template <typename _type>
class matrix2D : public baseMatrix<_type> {
public:
matrix2D(int _rows, int _cols);
matrix2D(int _rows, int _cols, _type _val);
~matrix2D();
_type& operator()(int _r, int _c);
_type& at(int _r, int _c);
protected:
int nRows,nCols;
using baseMatrix<_type>::data;
};
但是,实例化这些类时,我只能调用标量运算符,例如使用*=
和两个matrix2D
对象导致编译错误:
In file included from test.cpp:1:
baseMatrix.hpp: In instantiation of ‘baseMatrix<_type>& baseMatrix<_type>::operator*=(_input_type) [with _input_type = matrix2D<float>; _type = float]’:
test.cpp:29:6: required from here
baseMatrix.hpp:56:47: error: no match for ‘operator*=’ (operand types are ‘__gnu_cxx::__alloc_traits<std::allocator<float>, float>::value_type’ {aka ‘float’} and ‘matrix2D<float>’)
for (int i = 0; i < data.size(); ++i) data[i]*=_val;
另一方面,如果我实例化一个baseMatrix
对象,则它会编译OK(在运行时由于其他原因,即单元化数据而失败):
int main(int argc, char const *argv[]){
matrix2D<float> M1(5,5,0.0);
matrix2D<float> M2(3,3,6.0);
baseMatrix<float> testM;
M2*=0.47; // works
M2*=M1; // does not compile
M2*=testM // runtime error (segfault)
}
显然,运算符重载不适用于派生类,正确的语法是什么?
编辑:我已经意识到问题出在多个操作符重载上。由于某种原因,如果我仅声明运算符以baseMatrix
对象作为参数,反之亦然。
答案 0 :(得分:1)
因此对于M1*=M2
,过载解析检查以查看operator*=(M1, M2)
和/或M1.operator*=(M2)
是否可行。没有非成员operator*=
的优秀候选人。由于M1
的类型为matrix2D<float>
,它继承了baseMatrix<float>
,因此编译器会看到M1
具有成员函数:
template <typename _input_type> baseMatrix<float>& operator*= (_input_type _val); // #1
template <typename _input_type> baseMatrix<float>& operator*= (const baseMatrix<_input_type>& _mat); // #2
下一步是尝试为过载集中的每个模板推导模板参数。两者都成功:对于模板#1,仅采用_input_type = matrix2D<float>
就可以找到有效的专业化名称:
baseMatrix<float>& baseMatrix<float>::operator*=<matrix2D<float>>(matrix2D<float> _val); // #3
对于模板2,它通过使用M2
参数类型的基类并确定_input_type = float
来找到特化项:
baseMatrix<float>& baseMatrix<float>::operator*=<float>(const baseMatrix<float>& _val); // #4
然后比较这些功能模板的专长。这里的问题是您打算使用#4,但是#3被认为比#4更好,因为#3使用了确切类型的参数M2
,但是#4需要派生到基数的转换。然后,#3的实例包含语句data[i]*=_val;
对于data[i]
a float
和_val
a matrix2D<float>
来说是没有意义的,从而导致错误。 / p>
一种解决方案是使用SFINAE技术确保模板#1不能与矩阵类型一起使用:
#include <utility>
#include <type_traits>
template <typename Type>
class baseMatrix {
private:
template <typename ValType>
static constexpr std::true_type is_matrix_ptr(const baseMatrix<ValType>*);
static constexpr std::false_type is_matrix_ptr(const void*);
public:
// ...
template <typename ScalarType,
std::enable_if_t<!decltype(is_matrix_ptr(std::declval<ScalarType*>()))
::value>* = nullptr>
baseMatrix& operator*=(ScalarType val);
// ...
};