【问题标题】:No match operator for 'operator *' in MatrixMatrix 中没有“运算符 *”的匹配运算符
【发布时间】:2012-01-25 02:23:50
【问题描述】:

我有一个如下的矩阵类:

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,这个运算符在'+'运算符之前调用,但我不知道为什么它不能为'*'运算符执行!

【问题讨论】:

    标签: c++ templates casting operators


    【解决方案1】:

    这个问题或多或少是经典的。重载决议开始于 建立一个可能的功能列表;在这种情况下,函数名为 operator*。为此,它添加了所有 operator* 函数 范围到列表,它尝试通过实例化所有函数模板 应用类型扣除;如果类型推导成功,则添加 将模板实例化到列表中。 (函数模板是 不是函数。函数模板的实例化是 功能。)

    模板类型推导的规则与 重载决议。特别是,只有非常小的一组 考虑转换。用户定义的转换运算符不是 经过考虑的。结果是在m1 * m2 中,为 operator* 失败(因为它需要一个不是 经过考虑的)。所以没有函数模板的实例被添加到 列表中,没有其他operator*

    更一般地说:你是 operator T2() 不允许类型推导 即使被允许;有无数次转换 这将匹配operator*。事实上,我怀疑你已经成功了 太笼统;你想要一个operator Matrix&lt;M, N, T2&gt;()。 (不是那个 这在这里会有所帮助,但在某些情况下它可能会消除 模棱两可。)

    你可以通过定义一个:

    template<size_t P, tyepname OtherT>
    Matrix<M, P, T> operator*( Matrix<N, P, T> const& rhs ) const;
    

    ,然后在 operator* 中进行转换。 (我没试过, 我不确定,但我认为你现有的operator* 应该是 被认为是“更专业的”,因此在键入时被选择 两者都扣除成功。)

    话虽如此,我认为你这样做的方式是错误的。 你真的希望m1 * m2m2 * m1 的返回类型是 不同的。对于初学者,我需要客户端代码来制作 显式转换(在您当前的代码中就是这种情况);如果你这样做 想要支持隐式转换,我认为您需要进行 operator* 一个全局的,使用某种简单的元编程来 确定正确的返回类型(即给定矩阵 longunsigned,您可能希望返回类型为 unsigned long, 因为这是这些类型的混合类型算术给出的 否则),将两边转换为目标类型,并进行算术运算 在上面。很多工作可能不是很重要或 有用的功能。 (当然,只是我的看法。如果你的客户真的 想要混合类型的算术,并且愿意为此付费...)

    【讨论】:

      【解决方案2】:

      隐式转换是您示例中的罪魁祸首(m1 * m1 有效)。虽然我的语言不够坚定,无法确切地告诉您原因,但我怀疑模板化的 operator* 方法(没有准确指定类型)和必要的类型转换的组合有太多的歧义。编译器被告知它可以将您的矩阵转换为任何类型,并且模板化的类型族可能是operator* 的有效参数。 在确定从这些方法调用哪个operator* 时会遇到问题。插入static_cast 作为m1 * static_cast&lt; Matrix&lt;10,10,int&gt; &gt;(m2) 证实了这种怀疑。

      Eigen 库是一个相当成熟且非常好的矩阵库,它们也不进行隐式标量转换。相反,他们使用了 cast 方法:

      template <typename Scalar> Matrix<M,N,Scalar> cast() const;
      

      在你的例子中,你会写:

      m1.cast<float>() * m2;  
      

      【讨论】:

      • 是的,我之前尝试过m1.cast&lt;float&gt;() 之类的东西,效果很好。但是隐式转换的好处是像 float->float 这样的转换可以被编译器丢弃。但是当我使用cast&lt;float&gt;() 时,即使对于 float->float,也会进行强制转换。
      • @MasoudM:为不必要的演员添加专业化。 boost::is_same&lt;Scalar,T&gt; 是你的朋友。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-25
      • 1970-01-01
      • 2016-02-12
      • 2012-03-12
      • 2013-09-29
      • 2017-02-07
      相关资源
      最近更新 更多