TLDR;我想使用为我的班级定义的运算符,并使用原始数据类型将其转换为我的班级,而无需类型转换/初始化新变量。即
mycomplex x = 5 , y ;
y = x + 3 ;
作为辅助项目,我正在开发一个复数类。出于明显的原因,任何原始数字数据类型都可以解释为复数。因此,在任何涉及原始类型和复数的运算中,我都希望允许原始类型转换为复数,并使用定义的涉及两个复数的运算继续运算。
每个基本类型都可以在每个运算符上重载,但是顺序很重要,并且具有4个基本运算符和一些更高的数学功能,它将很快变成大量代码。所以问题是,如何编写我的类,以使原始类型可以“投射”到复杂对象并执行常规的复杂操作。
如果注释掉main的倒数第二行,则此代码编译。这里的目标是使该行评估为cout为8 + 2i的mycomplex。
#include <iostream>
template <class T>
class mycomplex{
private:
T real ;
T imag ;
public:
mycomplex( const mycomplex<T> & x ) ;
mycomplex( const T & realx , const T & imagx ) ;
mycomplex( const T & x ) ;
mycomplex( ) ;
template <class U>
friend std::ostream & operator << ( std::ostream & os , const mycomplex<U> & x ) ;
template <class U>
friend mycomplex<U> operator + ( const mycomplex<U> & lhs , const mycomplex<U> & rhs ) ;
} ;
int main( int argc , char * argv[] ){
mycomplex<float> x = 5 , y( 3 , 2 ) ;
mycomplex<float> z = y + x ;
std::cout << x << '\n' << y << '\n' << z << std::endl ;
z = 5 + y ;
return 0 ;
}
template <class T>
mycomplex<T>::mycomplex( const mycomplex<T> & x ){
real = x.real ;
imag = x.imag ;
}
template <class T>
mycomplex<T>::mycomplex( const T & realx , const T & imagx ){
real = realx ;
imag = imagx ;
}
template <class T>
mycomplex<T>::mycomplex( const T & x ){
real = x ;
imag = 0 ;
}
template <class T>
mycomplex<T>::mycomplex( ){
real = 0 ;
imag = 0 ;
}
template <class T>
std::ostream & operator << ( std::ostream & os , const mycomplex<T> & x ){
os << x.real ;
if( x.imag >= 0 )
os << "+" ;
os << x.imag << "i" ;
return os ;
}
template <class T>
mycomplex<T> operator + ( const mycomplex<T> & lhs , const mycomplex<T> & rhs ){
mycomplex<T> ans ;
ans.real = lhs.real + rhs.real ;
ans.imag = lhs.imag + rhs.imag ;
return ans ;
}
我查看了this answer并实现了该功能,如您在上面看到的那样,但这虽然让您在声明变量时很方便,却无法让此编译。我还查看了this answer,并在模板类型中添加了类型转换,但这使我的班级转到模板,这与目标恰好相反。它允许编译上面的代码,但是任何mycomplex + T都会给出没有虚部的mycomplex,这是不正确的。
答案 0 :(得分:1)
您可以使用std :: enable_if,但这非常难看。
我很着急,所以很遗憾,我没有对此进行广泛的测试或启用促销活动(float
+ complex<int>
给您complex<float>
)。
可运行的代码here。
#include <iostream>
#include <type_traits>
template <class T>
class mycomplex{
private:
T r ;
T i ;
public:
using Underlying = T;
mycomplex( const mycomplex<T> & x ) ;
mycomplex( const T & realx , const T & imagx ) ;
mycomplex( const T & x ) ;
mycomplex( ) ;
T real() const{
return r;
}
T imag() const {
return i;
}
template <class U>
friend std::ostream & operator << ( std::ostream & os , const mycomplex<U> & x ) ;
} ;
template <class T>
mycomplex<T>::mycomplex( const mycomplex<T> & x ){
r = x.r ;
i = x.i ;
}
template <class T>
mycomplex<T>::mycomplex( const T & realx , const T & imagx ){
r = realx ;
i = imagx ;
}
template <class T>
mycomplex<T>::mycomplex( const T & x ){
r = x ;
i = 0 ;
}
template <class T>
mycomplex<T>::mycomplex( ){
r = 0 ;
i = 0 ;
}
template <class T>
std::ostream & operator << ( std::ostream & os , const mycomplex<T> & x ){
os << x.r ;
if( x.i >= 0 )
os << "+" ;
os << x.i << "i" ;
return os ;
}
template<typename T>
struct is_mycomplex : std::false_type{
};
template<typename T>
struct is_mycomplex<mycomplex<T>> : std::true_type{
};
static_assert(!is_mycomplex<int>::value);
static_assert(is_mycomplex<mycomplex<int>>::value);
template <typename T>
auto type_helper(){
if constexpr (is_mycomplex<T>::value){
return typename T::Underlying{};
} else {
return T{};
}
}
template <class L, class R, typename = std::enable_if_t<
is_mycomplex<L>::value + is_mycomplex<R>::value == 2
||
(is_mycomplex<L>::value + is_mycomplex<R>::value == 1
&&
std::is_arithmetic_v<L> + std::is_arithmetic_v<R> ==1)
>>
auto operator + ( const L& lhs , const R& rhs ){
using T = decltype(type_helper<L>());
T real = 0;
T imag = 0;
if constexpr(std::is_arithmetic_v<L>) {
real+=lhs;
} else {
real+=lhs.real();
imag+=lhs.imag();
}
if constexpr(std::is_arithmetic_v<R>) {
real+=rhs;
} else {
real+=rhs.real();
imag+=rhs.imag();
}
return mycomplex<T>(real, imag);
;
}
int main(){
mycomplex<float> x = 5 , y( 3 , 2 ) ;
mycomplex<float> z = y + x ;
std::cout << x << '\n' << y << '\n' << z << std::endl ;
z = 5.5f + y ;
std::cout << "\n\n" << z << std::endl ;
}
答案 1 :(得分:0)
让我们看看这一行:
z = 5 + y ;
在y
为mycomplex<float>
的情况下,编译器首先寻找operator+
的重载,该重载取一个整数(文字5
的类型是整数)和{{ 1}}。这个不存在,唯一的mycomplex<float>
带有两个operator+
值。
由于mycomplex
已经是y
类型,因此编译器将尝试将mycomplex
转换为5
。这将是不可能的,因为您只能将mycomplex<float>
的值转换为float
。
在这一点上很明显,没有可用的重载,也没有转换将使该行格式正确。编译终止。
一种可能的解决方案是创建一个从任何内容到mycomplex<float>
的转换运算符,并将其仅用于数字类型。
类似的东西:
mycomplex