模板运算符的不明确重载
-
06-07-2019 - |
题
我正在研究两个定义真实数据类型和复杂数据类型的包装类。每个类都定义了重载构造函数,以及四个算术运算符 +、-、*、/ 和五个赋值运算符 =、+= 等。为了避免重复代码,当运算符的左侧和右侧参数具有不同的数据类型时,我考虑使用模板函数:
// real.h
class Real {
public:
explicit Real(const double& argument) {...}
explicit Real(int argument) {...}
...
friend const operator*(const Real&; const Real&);
template <class T> friend const Real operator*(const Real&, const T&);
template <class T> friend const Real operator*(const T&, cont Real&);
// Here, T is meant to be a template parameter for double and int
// Repeat for all other arithmetic and assignment operators
};
// complex.h
class Complex {
public:
explicit Complex(const Real& realPart) {...}
explicit Complex(const Real& realPart, const Real& imaginaryPart) {...}
// Overload for double and int data types
...
friend const operator*(const Complex&, const Complex&);
template <class T> friend const Complex operator*(const Complex&, const T&);
template <class T> friend const Complex operator*(const T&, cont Complex&);
// Here, T is is a template parameter for Real, double and int
...
};
这里的问题是这样的代码:
//main.cpp
void main() {
Complex ac(2.0, 3.0);
Real br(2.0);
Complex cc = ac * br;
}
返回编译器(海湾合作委员会) 错误 “ac * br”中“operator*”的重载不明确, ,因为编译器无法区分:
template <class T> friend const Complex operator*(const Complex&, const T&)
[其中 T = 实数]template <class T> friend const Real operator*(const T&, cont Real&)
[其中 T = 复数]
有没有办法指定 T 不能是类 Real 中模板运算符 * 定义中的复数?或者我是否必须不用模板并为参数数据类型的每种可能的组合定义每个运算符?或者有没有办法重新设计代码?
解决方案
啊,运营商的问题……
Boost 创建了一个很好的库,因此通过提供最少的逻辑,所有其他变体都会自动为您添加!
看一眼 Boost.算子 !
现在,对于您的问题,实际上正如您所注意到的,您必须定义两种类型的运算符(int 和 double),而不是使用通用模板。如果这些运算符中有很多逻辑(我对此表示怀疑),那么您始终可以让它们调用通用(模板化)方法。
template <typename T>
Complex complex_mult_impl(T const& lhs, Complex const& rhs) { ... } // Note (1)
// return type is not 'Complex const', see (2)
Complex operator*(int lhs, Complex const& rhs)
{
return complex_mult_impl(lhs,rhs);
}
但是,如果您使用 Boost.operators,则只需提供 Complex::operator*=(int) 和 Complex::operator*=(double) ,并且将自动推导出独立版本:)
(1) 如果所有参数都是内置参数,则可以在此处使用按值传递。您可能还想考虑 Boost.CallTraits, ,它会自动在按值和按引用之间进行选择,具体取决于参数是否内置。对于模板来说很方便。
(2) 当按值返回参数时,将它们限定为没有意义 const
. 。这 const
关键字仅意味着引用和指针,这里没有什么可以阻止用户实例化“简单” Complex
...你很幸运,事实并非如此!
其他提示
您可以使 Real 或 Complex 类具有非全局乘法运算符。
class Real
{
........
template <class T> const Real operator*(const T&);
const Real operator*(const Real&);
};
你能让复杂的构造函数显式化吗?这意味着不允许从实数到复数的隐式转换,并且应该消除运算符 * 的歧义