【发布时间】:2019-11-06 11:48:35
【问题描述】:
我正在编写一些模板库(假设是线性代数库)并遇到了下一个复杂的错误,我只能在 GCC 上重现该错误(Clang 和 VC++ 按预期工作)。
该库由通用模板类型组成,例如
template<class C, int N>
class Vector;
template<class C, int N, int M = N>
class Matrix;
有一些默认实现不使用。 还有一组像这样的接口类
template<class C, int N>
struct VecMulInterface
{
Vector<C, N> operator*(const Vector<C, N>& v)
{
return static_cast<Matrix<C, N, N>*>(this)->mul_impl(v);
}
};
template<class C, int N>
struct ScalMulInterface
{
Matrix<C, N, N> operator*(const C& c)
{
return static_cast<Matrix<C, N, N>*>(this)->mul_impl(c);
}
};
以及相应的实现提供者
template<class C, int N>
struct MulImpl
{
public:
Vector<C, N> mul_impl(const Vector<C, N>& v) const
{
return {}; // imagine some logic here
}
Matrix<C, N, N> mul_impl(const C& c) const
{
return {}; // imagine some logic here
}
};
最后我有了模板专业化,这些模板使用了上面的所有内容:
template<class C>
class Vector<C, 2>
{
public:
C items[2];
// ...
};
template<class C>
class Matrix<C, 2, 2>:
public VecMulInterface<C, 2>,
public ScalMulInterface<C, 2>,
public MulImpl<C, 2>
{
public:
C items[4];
// ...
};
我尝试像这样使用它们:
Matrix<int, 2, 2> m;
Vector<int, 2> v1, v2;
v2 = m * v1; // <- error
现在 GCC 产生一个错误“错误:对成员 ‘operator*’ 的请求不明确”。 但! 如果我更改错误行,以便我使用重载函数而不是 'operator*'
v2 = m.mul_impl( v1 ); // <- NO error
或者,如果不是从各自的接口继承,而是将运算符置于类外,如下所示:
template<class C, int N>
Vector<C, N> operator*(const Matrix<C, N, N>& m, const Vector<C, N>& v)
{
return m.mul_impl(v);
}
template<class C, int N>
Matrix<C, N, N> operator*(const Matrix<C, N, N>& m, const C& c)
{
return m.mul_impl(c);
}
一切正常。 (VC++ 和 Clang 似乎在所有情况下都能正常工作)
谁能解释这种行为的原因?这是编译器错误还是我在代码中的某处踩到了“未定义的行为”?
【问题讨论】:
标签: c++ templates inheritance operator-overloading