我正在努力实现复数。类Complex
有两个私有成员real_part
和imaginary_part
。我想覆盖乘法运算,如下所示:
template<typename T, typename D>
friend Complex operator * (T lhs, D rhs)
{
double real_a;
double real_b;
double imaginary_a;
double imaginary_b;
if(std::is_same<T, Complex>::value)//if lhs is a Complex
{
real_a = lhs.real_part;
imaginary_a = lhs.imaginary_part;
}
else //base type, some sort of number
{
real_a = lhs;
imaginary_a = 0;
}
if(std::is_same<D, Complex>::value)//if rhs is a Complex
{
real_b = rhs.real_part;
imaginary_b = rhs.imaginary_part;
}
else //base type, some sort of number
{
real_b = rhs;
imaginary_b = 0;
}
Complex result;
result.real_part = (real_b*real_a- imaginary_b*imaginary_a);
result.imaginary_part = (real_b*imaginary_a + imaginary_b*real_a);
return result;
}
我的构造函数如下:
Complex::Complex()
{
real_part = 0.0;
imaginary_part = 0.0;
}
和:
Complex(T real, T imaginary)
{
real_part = real;
imaginary_part = imaginary;
}
当我尝试将两个Complex乘在一起时:
Complex a(4.0, 8.0);
Complex b(8, 16);
auto prod = a*b;
auto prod2 = a * 2;
我收到以下错误:
In file included from main.cpp:2:
complex.hpp: In instantiation of ‘Complex operator*(T, D) [with T = Complex; D = Complex]’:
main.cpp:13:17: required from here
complex.hpp:43:16: error: cannot convert ‘Complex’ to ‘double’ in assignment
real_a = lhs;
~~~~~~~^~~~~
complex.hpp:53:16: error: cannot convert ‘Complex’ to ‘double’ in assignment
real_b = rhs;
~~~~~~~^~~~~
complex.hpp: In instantiation of ‘Complex operator*(T, D) [with T = Complex; D = int]’:
main.cpp:14:20: required from here
complex.hpp:43:16: error: cannot convert ‘Complex’ to ‘double’ in assignment
real_a = lhs;
~~~~~~~^~~~~
complex.hpp:48:22: error: request for member ‘real_part’ in ‘rhs’, which is of non-class type ‘int’
real_b = rhs.real_part;
~~~~^~~~~~~~~
complex.hpp:49:27: error: request for member ‘imaginary_part’ in ‘rhs’, which is of non-class type ‘int’
imaginary_b = rhs.imaginary_part;
~~~~^~~~~~~~~~~~~~
我正在尝试以这种方式对操作符进行重载(使用两种泛型类型),以避免使用多个重载乘法运算符(即LHS是泛型,而RHS是Complex类型,反之亦然,等等)。非常感谢您的帮助,因为我不确定自己在做什么错。
答案 0 :(得分:1)
这是因为if
的两个分支都针对相同的实例进行了编译。其中一些实例是无效的。
如果可以使用c ++ 17,则可以将if
替换为if constexr
,这样只能实例化正确的分支:
if constexpr (std::is_same<T, Complex>::value)//if lhs is a Complex
{
real_a = lhs.real_part;
imaginary_a = lhs.imaginary_part;
}
else //base type, some sort of number
{
real_a = lhs;
imaginary_a = 0;
}
if constexpr (std::is_same<D, Complex>::value)//if rhs is a Complex
{
real_b = rhs.real_part;
imaginary_b = rhs.imaginary_part;
}
else //base type, some sort of number
{
real_b = rhs;
imaginary_b = 0;
}
对于严格的C ++ 11,可以使用函数重载来区分这两种类型:
template<typename T>
static T getReal(T x)
{
return x;
}
static double getReal(Complex x)
{
return x.real_part;
}
template<typename T>
static T getImaginary(T x)
{
return 0;
}
static double getImaginary(Complex x)
{
return x.imaginary_part;
}
template<typename T, typename D>
friend Complex operator * (T lhs, D rhs)
{
double real_a = getReal(lhs);
double real_b = getReal(rhs);
double imaginary_a = getImaginary(lhs);
double imaginary_b = getImaginary(rhs);
Complex result;
result.real_part = (real_b*real_a- imaginary_b*imaginary_a);
result.imaginary_part = (real_b*imaginary_a + imaginary_b*real_a);
return result;
}
答案 1 :(得分:1)
模板的实例化必须完整地进行类型检查。
虽然您可以在编译时使用if constexpr
选择一个分支,但我认为这实际上是一种老式的方式,没有重载且没有条件:
// Mutating multiplication as a member
template<typename T>
Complex<T>& Complex<T>::operator*=(const Complex<T>& rhs)
{
auto real = real_part;
auto imaginary = imaginary_part;
real_part = real * rhs.real_part - imaginary * rhs.imaginary_part;
imaginary_part = imaginary * rhs.real_part + real * rhs.imaginary_part;
return *this;
}
// These are free non-friend functions.
template<typename T>
Complex<T> operator*(Complex<T> lhs, const Complex<T>& rhs)
{
return lhs *= rhs;
}
template<typename T>
Complex<T> operator*(const Complex<T>& lhs, T rhs)
{
return lhs * Complex(rhs, 0);
}
template<typename T>
Complex<T> operator*(T lhs, const Complex<T>& rhs)
{
return rhs * lhs;
}
答案 2 :(得分:1)
我同意Michael Veksler's answer,即 的基本规则,即模板函数将根据调用函数的方式编译为多个实例。但是,将在运行时对std::is_same
的断言进行所有代码的编译。因此,编译不会通过,因为您的代码的某些分支对于特定的参数类型(例如int
操作的rhs.real_part
)无效。
为简化代码,我们可以为Complex
类型定义另一个构造函数,以将其他数字类型( eg ,int
或double
)首先转换为Complex
类型。
template<typename T>
Complex(T real, T imaginary = 0)
{
real_part = real;
imaginary_part = imaginary;
}
然后我们可以将*
运算符重载函数修改为
static Complex operator * (const Complex & lhs, const Complex & rhs)
{
Complex result(lhs.real_part*rhs.real_part - lhs.imaginary_part * rhs.imaginary_part,
lhs.real_part*rhs.imaginary_part + lhs.imaginary_part * rhs.real_part);
return result;
}
请注意:新定义的构造函数或副本构造函数会将输入参数自动广播为Complex
类型。另外,返回的result
是使用新的Constructor构造的。