通过继承重载运算符会导致歧义
Operator overloading through inheritance causes ambiguity
我正在编写一些模板库(比如说线性代数库(,并遇到了下一个复杂的错误,我只能在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产生一个错误"error:对成员'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似乎在所有情况下都能正常工作(
有人能解释这种行为的原因吗?这是编译器错误还是我在代码中的某个地方出现了"未定义行为"?
不同作用域中的函数不会重载。对于成员operator*
的情况,这两个函数分别位于VecMulInterface
和ScalMulInterface
中,因此它们处于不同的范围中。在另外两种情况下,这两种功能在同一范围内。
您可以使用using声明将它们提升到相同的范围:
template<class C>
class Matrix<C, 2, 2> :
public VecMulInterface<C, 2>,
public ScalMulInterface<C, 2>,
public MulImpl<C, 2>
{
public:
using VecMulInterface<C, 2>::operator*;
using ScalMulInterface<C, 2>::operator*;
// ...
};
一种更优雅的方法是在接口中使用friend
函数:
template <class C, int N>
struct VecMulInterface
{
friend Vector<C, N> operator*(const Matrix<C, N, N>& m, const Vector<C, N>& v)
{
return m.mul_impl(m, v);
}
};
相关文章:
- 为什么比较运算符如此快速
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 消除好友和成员二进制运算符的歧义
- 如何在模板化转换运算符中消除此构造的歧义?
- C++ 类的构造函数和函数调用运算符 () 重载之间的歧义
- 通过继承重载运算符会导致歧义
- 运算符的歧义错误<<自定义 std::ostream 子类中的重载
- 将文本文件数据读入字符数组时提取运算符的歧义
- 转换运算符重载歧义,编译器不同
- 模板运算符似乎因歧义而失败
- 嵌套类中对运算符[]的调用存在歧义
- C++重载I/O运算符:克服歧义
- 与 [] 运算符和多重继承的歧义
- C++ "std::cin >>"中的"运算符>>"的歧义
- g++和clang++-删除由重载转换运算符歧义获取的指针
- 在C++中重载运算符时,如何防止整数歧义
- 运算符() 重载和函数对象中的 c'tor 歧义
- 运算符=与转换运算符结合时的歧义
- 转换运算符重载 - 函数歧义
- 重载运算符 == 和 != :编译器抱怨歧义