我有一个矩阵类,如下所示:
template <size_t M, size_t N, typename T>
class Matrix
{
public:
Matrix<M, N, T> operator +(const Matrix<M, N, T>& B) const;
template <size_t P> Matrix<M,P,T> operator*(const Matrix<N, P, T>& B) const;
template <typename T2> operator T2() const;
private:
T data[M][N];
};
// ... the body is in header file too ...//
身体写得很好,一切都运作良好。 当我定义两个矩阵时如下:
Matrix < 10, 10, int> m1;
Matrix < 10, 10, float> m2;
m1 + m2; // OK
m1 * m2; // error: no match for 'operator*' in 'm1 * m2'
第一个'+'运算符运行良好,因为已对其执行了隐式转换。 但是对于不同值类型的第二个'*'运算符,会发生错误。
错误:'m1 * m2'中的'operator *'不匹配
有什么想法吗?!
更新 所有代码都在头文件中。我没有问题,但对于'*'运算符。
关于'+'运算符你能说什么?我知道关于模板/运算符/转换的一切......但是这个问题就像我的gcc编译器的一个错误!?我写了一个cast-operator,这个运算符在'+'运算符之前调用,但我不知道为什么它不能为'*'运算符执行!
答案 0 :(得分:6)
问题或多或少是经典的。重载决议开始于
建立可能的功能列表;在这种情况下,函数命名
operator*
。为此,它添加了所有operator*
函数
范围到列表,它尝试通过实例化所有函数模板
申请类型扣除;如果类型扣除成功,它会添加
将模板实例化到列表中。 (功能模板是
不一个功能。函数模板的实例化是a
功能。)
模板类型推导的规则与使用的规则不同
超载分辨率。特别是,只有一小部分
转换被考虑。用户定义的转换运算符不是
考虑。结果是m1 * m2
中的类型扣除
operator*
失败(因为它需要转换而不是
考虑)。因此,不添加函数模板的实例化
列表,没有其他operator*
。
更一般地说:你operator T2()
不允许类型扣除
即使它被允许;转化次数无限
哪个匹配operator*
。事实上,我怀疑你已经做到了
太笼统了;你想要一个operator Matrix<M, N, T2>()
。 (不是那个
这在这里会有所帮助,但有些情况可能会消除
多义性。)
您可以通过定义:
来使其工作template<size_t P, tyepname OtherT>
Matrix<M, P, T> operator*( Matrix<N, P, T> const& rhs ) const;
,然后在运营商*内进行转换。 (我没试过,
我不确定,但我认为你现有的operator*
应该是
被认为是“更专业化”,因此在选择时选择
扣除成功。)
话虽如此,我认为你这样做的方法是错误的。
您真的想要m1 * m2
和m2 * m1
的返回类型吗?
不同。对于初学者,我需要客户端代码来制作
转换显式(在当前代码中就是这种情况);如果你这样做
想要支持隐式转换,我想你需要做的
operator*
全局,使用某种简单的元编程
确定正确的返回类型(即给定long
的矩阵和
unsigned
,您可能希望返回类型为unsigned long
,
因为这是这些类型的混合型算术给出的
否则),将双方转换为目标类型,并进行算术运算
在上面。很多工作可能不是很重要或者
有用的功能。 (当然,我的意见。如果你的客户真的
想要混合型算术,并且愿意付钱......)
答案 1 :(得分:2)
隐式演员是你的例子中的罪魁祸首(m1 * m1
起作用)。虽然我的语言不够完整,无法告诉您具体原因,但我怀疑模板化运算符*方法(未完全指定类型)与必要类型转换的组合具有太多歧义。编译器被告知它可以将矩阵转换为任何类型,并且模板化类型族可以是operator*
的有效参数。 我在确定从这些方法调用哪个operator*
时会遇到问题。将static_cast
作为m1 * static_cast< Matrix<10,10,int> >(m2)
插入可以确认这一点。
Eigen库是一个相当成熟且非常好的矩阵库,它们也不会进行隐式标量转换。相反,他们使用了一种演员方法:
template <typename Scalar> Matrix<M,N,Scalar> cast() const;
在你的例子中,你写道:
m1.cast<float>() * m2;